Shellvars: exclude more tcsh profile scripts (#627)

Found tcsh profile scripts also with the .tcsh extension, so exclude
them too.

Followup of commit b78bbb61282208288f0182ec1a9b3045c1f61e2a.

(*
Module: Shellvars
 Generic lens for shell-script config files like the ones found
 in /etc/sysconfig

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  (* Delete a blank line, rather than mapping it *)
  let del_empty = del (Util.empty_generic_re . "\n") "\n"

  let empty   = Util.empty
  let empty_part_re = Util.empty_generic_re . /\n+/
  let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n"
  let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"
  let brace_eol = del /[ \t\n]+/ "\n"

  let key_re = /[A-Za-z0-9_][-A-Za-z0-9_]*(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export")
  let matching_re = "${!" . key_re . /[\*@]\}/
  let eq = Util.del_str "="

  let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
  let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment
  (* comment_eol in shell MUST begin with a space *)
  let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
  let comment_or_eol = comment_eol | semicol_eol

  let xchgs   = Build.xchgs
  let semicol = del /;?/ ""

  let char  = /[^`;()'"&|\n\\# \t]#*|\\\\./
  let dquot =
       let char = /[^"\\]|\\\\./ | Rx.cl
    in "\"" . char* . "\""                    (* " Emacs, relax *)
  let squot = /'[^']*'/
  let bquot = /`[^`\n]+`/
  (* dbquot don't take spaces or semi-colons *)
  let dbquot = /``[^` \t\n;]+``/
  let dollar_assign = /\$\([^\(\)#\n]*\)/
  let dollar_arithm = /\$\(\([^\)#\n]*\)\)/

  let anyquot = (char|dquot|squot|dollar_assign|dollar_arithm)+ | bquot | dbquot
  let sto_to_semicol = store (anyquot . (Rx.cl_or_space . anyquot)*)

  (* Array values of the form '(val1 val2 val3)'. We do not handle empty *)
  (* arrays here because of typechecking headaches. Instead, they are    *)
  (* treated as a simple value                                           *)
  let array =
    let array_value = store anyquot in
    del /\([ \t]*/ "(" . counter "values" .
      [ seq "values" . array_value ] .
      [ del /[ \t\n]+/ " " . seq "values" . array_value ] *
      . del /[ \t]*\)/ ")"

  (* Treat an empty list () as a value '()'; that's not quite correct *)
  (* but fairly close.                                                *)
  let simple_value =
    let empty_array = /\([ \t]*\)/ in
      store (anyquot | empty_array)?

  let export = [ key "export" . Util.del_ws_spc ]
  let kv = Util.indent . export? . key key_re
           . eq . (simple_value | array)

  let var_action (name:string) =
    Util.indent . del name name . Util.del_ws_spc
    . label ("@" . name) . counter "var_action"
    . Build.opt_list [ seq "var_action" . store (key_re | matching_re) ] Util.del_ws_spc

  let unset = var_action "unset"
  let bare_export = var_action "export"

  let source =
    Util.indent
    . del /\.|source/ "." . label ".source"
    . Util.del_ws_spc . store /[^;=# \t\n]+/

  let shell_builtin_cmds = "ulimit" | "shift" | "exit"

  let eval =
    Util.indent . Util.del_str "eval" . Util.del_ws_spc
    . label "@eval" . store anyquot

  let alias =
    Util.indent . Util.del_str "alias" . Util.del_ws_spc
    . label "@alias" . store key_re . eq
    . [ label "value" . store anyquot ]

  let builtin =
    Util.indent . label "@builtin"
    . store shell_builtin_cmds
    . (Sep.cl_or_space
    . [ label "args" . sto_to_semicol ])?

  let keyword (kw:string) = Util.indent . Util.del_str kw
  let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl

  let return =
    Util.indent . label "@return"
    . Util.del_str "return"
    . ( Util.del_ws_spc . store Rx.integer )?

  let action (operator:string) (lbl:string) (sto:lens) =
       let sp = Rx.cl_or_opt_space | /[ \t\n]+/
    in [ del (sp . operator . sp) (" " . operator . " ")
       . label ("@".lbl) . sto ]

  let action_pipe = action "|" "pipe"
  let action_and = action "&&" "and"
  let action_or = action "||" "or"

  let condition =
    let cond (start:string) (end:string) = [ label "type" . store start ]
                                         . Util.del_ws_spc . sto_to_semicol
                                         . Util.del_ws_spc . Util.del_str end
                                         . ( action_and sto_to_semicol | action_or sto_to_semicol )*
    in Util.indent . label "@condition" . (cond "[" "]" | cond "[[" "]]")

  (* Entry types *)
  let entry_eol_item (item:lens) = [ item . comment_or_eol ]
  let entry_item (item:lens) = [ item ]

  let entry_eol_nocommand =
      entry_eol_item source
        | entry_eol_item kv
        | entry_eol_item unset
        | entry_eol_item bare_export
        | entry_eol_item builtin
        | entry_eol_item return
        | entry_eol_item condition
        | entry_eol_item eval
        | entry_eol_item alias

  let entry_noeol_nocommand =
      entry_item source
        | entry_item kv
        | entry_item unset
        | entry_item bare_export
        | entry_item builtin
        | entry_item return
        | entry_item condition
        | entry_item eval
        | entry_item alias

  (* Command *)
  let rec command =
       let env = [ key key_re . eq . store anyquot . Sep.cl_or_space ]
    in let reserved_key = /exit|shift|return|ulimit|unset|export|source|\.|if|for|select|while|until|then|else|fi|done|case|eval|alias/
    in let word = /\$?[-A-Za-z0-9_.\/]+/
    in let entry_eol = entry_eol_nocommand | entry_eol_item command
    in let entry_noeol = entry_noeol_nocommand | entry_item command
    in let entry = entry_eol | entry_noeol
    in let pipe = action_pipe (entry_eol_item command | entry_item command)
    in let and = action_and entry
    in let or = action_or entry
    in Util.indent . label "@command" . env* . store (word - reserved_key)
     . [ Sep.cl_or_space . label "@arg" . sto_to_semicol]?
     . ( pipe | and | or )?

  let entry_eol = entry_eol_nocommand
                | entry_eol_item command

  let entry_noeol = entry_noeol_nocommand
                  | entry_item command

(************************************************************************
 * Group:                 CONDITIONALS AND LOOPS
 *************************************************************************)

  let generic_cond_start (start_kw:string) (lbl:string)
                         (then_kw:string) (contents:lens) =
      keyword_label start_kw lbl . Sep.space
      . sto_to_semicol
      . ( action_and sto_to_semicol | action_or sto_to_semicol )*
      . semicol_eol
      . keyword then_kw . eol
      . contents

  let generic_cond (start_kw:string) (lbl:string)
                       (then_kw:string) (contents:lens) (end_kw:string) =
      [ generic_cond_start start_kw lbl then_kw contents
        . keyword end_kw . comment_or_eol ]

  let cond_if (entry:lens) =
    let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in
    let else = [ keyword_label "else" "@else" . eol . entry+ ] in
    generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi"

  let loop_for (entry:lens) =
    generic_cond "for" "@for" "do" entry+ "done"

  let loop_while (entry:lens) =
    generic_cond "while" "@while" "do" entry+ "done"

  let loop_until (entry:lens) =
    generic_cond "until" "@until" "do" entry+ "done"

  let loop_select (entry:lens) =
    generic_cond "select" "@select" "do" entry+ "done"

  let case (entry:lens) (entry_noeol:lens) =
       let pattern = [ label "@pattern" . sto_to_semicol . Sep.opt_space ]
    in let case_entry = [ label "@case_entry"
                       . Util.indent . pattern
                       . (Util.del_str "|" . Sep.opt_space . pattern)*
                       . Util.del_str ")" . eol
                       . entry* . entry_noeol?
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store (char+ | ("\"" . char+ . "\""))
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . (empty* . comment* . case_entry)*
        . empty* . comment*
        . keyword "esac" . comment_or_eol ]

  let subshell (entry:lens) =
    [ Util.indent . label "@subshell"
    . Util.del_str "{" . brace_eol
    . entry+
    . Util.indent . Util.del_str "}" . eol ]

  let function (entry:lens) (start_kw:string) (end_kw:string) =
    [ Util.indent . label "@function"
    . del /(function[ \t]+)?/ ""
    . store Rx.word . del /[ \t]*\(\)/ "()"
    . (comment_eol|brace_eol) . Util.del_str start_kw . brace_eol
    . entry+
    . Util.indent . Util.del_str end_kw . eol ]

  let rec rec_entry =
    let entry = comment | entry_eol | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry entry_noeol
      | function entry "{" "}"
      | function entry "(" ")"
      | subshell entry

  let lns_norec = del_empty* . (comment | entry_eol) *

  let lns = del_empty* . (comment | entry_eol | rec_entry) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))

  let filter_sysconfig =
      sc_incl "*" .
      sc_excl "anaconda" .
      sc_excl "bootloader" .
      sc_excl "hw-uuid" .
      sc_excl "hwconf" .
      sc_excl "ip*tables" .
      sc_excl "ip*tables.save" .
      sc_excl "kernel" .
      sc_excl "*.pub" .
      sc_excl "sysstat.ioconf" .
      sc_excl "system-config-firewall" .
      sc_excl "system-config-securitylevel" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_excl "network/if-up.d/SuSEfirewall2" .
      sc_incl "network/providers/*" .
      sc_excl "network-scripts" .
      sc_incl "network-scripts/ifcfg-*" .
      sc_excl "rhn" .
      sc_incl "rhn/allowed-actions/*" .
      sc_excl "rhn/allowed-actions/script" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd" .
      sc_excl "SuSEfirewall2.d" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_excl "SuSEfirewall2.d/services/TEMPLATE" .
      sc_excl "*.systemd"

  let filter_default = incl "/etc/default/*"
                     . excl "/etc/default/grub_installdevice*"
                     . excl "/etc/default/rmt"
                     . excl "/etc/default/star"
                     . excl "/etc/default/whoopsie"
                     . incl "/etc/profile"
                     . incl "/etc/profile.d/*"
                     . excl "/etc/profile.d/*.csh"
                     . excl "/etc/profile.d/*.tcsh"
                     . excl "/etc/profile.d/csh.local"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/conf.d/*"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"
                     . incl "/etc/firewalld/firewalld.conf"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/kamailio/kamctlrc"
                     . incl "/etc/lbu/lbu.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/os-release"
                     . incl "/etc/periodic.conf"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/rc.conf.d/*"
                     . incl "/etc/rc.conf.local"
                     . incl "/etc/selinux/config"
                     . incl "/etc/ucf.conf"
                     . incl "/etc/locale.conf"
                     . incl "/etc/vconsole.conf"
                     . incl "/etc/byobu/*"

  let filter = filter_sysconfig
             . filter_default
             . filter_misc
             . Util.stdexcl

  let xfm = transform lns filter

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)

(*
Module: Shellvars
 Generic lens for shell-script config files like the ones found
 in /etc/sysconfig

About: License
   This file is licenced under the LGPL v2+, like the rest of Augeas.

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  (* Delete a blank line, rather than mapping it *)
  let del_empty = del (Util.empty_generic_re . "\n") "\n"

  let empty   = Util.empty
  let empty_part_re = Util.empty_generic_re . /\n+/
  let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n"
  let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"
  let brace_eol = del /[ \t\n]+/ "\n"

  let key_re = /[A-Za-z0-9_][-A-Za-z0-9_]*(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export")
  let matching_re = "${!" . key_re . /[\*@]\}/
  let eq = Util.del_str "="

  let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n"
  let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment
  (* comment_eol in shell MUST begin with a space *)
  let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment
  let comment_or_eol = comment_eol | semicol_eol

  let xchgs   = Build.xchgs
  let semicol = del /;?/ ""

  let char  = /[^`;()'"&|\n\\# \t]#*|\\\\./
  let dquot =
       let char = /[^"\\]|\\\\./ | Rx.cl
    in "\"" . char* . "\""                    (* " Emacs, relax *)
  let squot = /'[^']*'/
  let bquot = /`[^`\n]+`/
  (* dbquot don't take spaces or semi-colons *)
  let dbquot = /``[^` \t\n;]+``/
  let dollar_assign = /\$\([^\(\)#\n]*\)/
  let dollar_arithm = /\$\(\([^\)#\n]*\)\)/

  let anyquot = (char|dquot|squot|dollar_assign|dollar_arithm)+ | bquot | dbquot
  let sto_to_semicol = store (anyquot . (Rx.cl_or_space . anyquot)*)

  (* Array values of the form '(val1 val2 val3)'. We do not handle empty *)
  (* arrays here because of typechecking headaches. Instead, they are    *)
  (* treated as a simple value                                           *)
  let array =
    let array_value = store anyquot in
    del /\([ \t]*/ "(" . counter "values" .
      [ seq "values" . array_value ] .
      [ del /[ \t\n]+/ " " . seq "values" . array_value ] *
      . del /[ \t]*\)/ ")"

  (* Treat an empty list () as a value '()'; that's not quite correct *)
  (* but fairly close.                                                *)
  let simple_value =
    let empty_array = /\([ \t]*\)/ in
      store (anyquot | empty_array)?

  let export = [ key "export" . Util.del_ws_spc ]
  let kv = Util.indent . export? . key key_re
           . eq . (simple_value | array)

  let var_action (name:string) =
    Util.indent . del name name . Util.del_ws_spc
    . label ("@" . name) . counter "var_action"
    . Build.opt_list [ seq "var_action" . store (key_re | matching_re) ] Util.del_ws_spc

  let unset = var_action "unset"
  let bare_export = var_action "export"

  let source =
    Util.indent
    . del /\.|source/ "." . label ".source"
    . Util.del_ws_spc . store /[^;=# \t\n]+/

  let shell_builtin_cmds = "ulimit" | "shift" | "exit"

  let eval =
    Util.indent . Util.del_str "eval" . Util.del_ws_spc
    . label "@eval" . store anyquot

  let alias =
    Util.indent . Util.del_str "alias" . Util.del_ws_spc
    . label "@alias" . store key_re . eq
    . [ label "value" . store anyquot ]

  let builtin =
    Util.indent . label "@builtin"
    . store shell_builtin_cmds
    . (Sep.cl_or_space
    . [ label "args" . sto_to_semicol ])?

  let keyword (kw:string) = Util.indent . Util.del_str kw
  let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl

  let return =
    Util.indent . label "@return"
    . Util.del_str "return"
    . ( Util.del_ws_spc . store Rx.integer )?

  let action (operator:string) (lbl:string) (sto:lens) =
       let sp = Rx.cl_or_opt_space | /[ \t\n]+/
    in [ del (sp . operator . sp) (" " . operator . " ")
       . label ("@".lbl) . sto ]

  let action_pipe = action "|" "pipe"
  let action_and = action "&&" "and"
  let action_or = action "||" "or"

  let condition =
    let cond (start:string) (end:string) = [ label "type" . store start ]
                                         . Util.del_ws_spc . sto_to_semicol
                                         . Util.del_ws_spc . Util.del_str end
                                         . ( action_and sto_to_semicol | action_or sto_to_semicol )*
    in Util.indent . label "@condition" . (cond "[" "]" | cond "[[" "]]")

  (* Entry types *)
  let entry_eol_item (item:lens) = [ item . comment_or_eol ]
  let entry_item (item:lens) = [ item ]

  let entry_eol_nocommand =
      entry_eol_item source
        | entry_eol_item kv
        | entry_eol_item unset
        | entry_eol_item bare_export
        | entry_eol_item builtin
        | entry_eol_item return
        | entry_eol_item condition
        | entry_eol_item eval
        | entry_eol_item alias

  let entry_noeol_nocommand =
      entry_item source
        | entry_item kv
        | entry_item unset
        | entry_item bare_export
        | entry_item builtin
        | entry_item return
        | entry_item condition
        | entry_item eval
        | entry_item alias

  (* Command *)
  let rec command =
       let env = [ key key_re . eq . store anyquot . Sep.cl_or_space ]
    in let reserved_key = /exit|shift|return|ulimit|unset|export|source|\.|if|for|select|while|until|then|else|fi|done|case|eval|alias/
    in let word = /\$?[-A-Za-z0-9_.\/]+/
    in let entry_eol = entry_eol_nocommand | entry_eol_item command
    in let entry_noeol = entry_noeol_nocommand | entry_item command
    in let entry = entry_eol | entry_noeol
    in let pipe = action_pipe (entry_eol_item command | entry_item command)
    in let and = action_and entry
    in let or = action_or entry
    in Util.indent . label "@command" . env* . store (word - reserved_key)
     . [ Sep.cl_or_space . label "@arg" . sto_to_semicol]?
     . ( pipe | and | or )?

  let entry_eol = entry_eol_nocommand
                | entry_eol_item command

  let entry_noeol = entry_noeol_nocommand
                  | entry_item command

(************************************************************************
 * Group:                 CONDITIONALS AND LOOPS
 *************************************************************************)

  let generic_cond_start (start_kw:string) (lbl:string)
                         (then_kw:string) (contents:lens) =
      keyword_label start_kw lbl . Sep.space
      . sto_to_semicol
      . ( action_and sto_to_semicol | action_or sto_to_semicol )*
      . semicol_eol
      . keyword then_kw . eol
      . contents

  let generic_cond (start_kw:string) (lbl:string)
                       (then_kw:string) (contents:lens) (end_kw:string) =
      [ generic_cond_start start_kw lbl then_kw contents
        . keyword end_kw . comment_or_eol ]

  let cond_if (entry:lens) =
    let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in
    let else = [ keyword_label "else" "@else" . eol . entry+ ] in
    generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi"

  let loop_for (entry:lens) =
    generic_cond "for" "@for" "do" entry+ "done"

  let loop_while (entry:lens) =
    generic_cond "while" "@while" "do" entry+ "done"

  let loop_until (entry:lens) =
    generic_cond "until" "@until" "do" entry+ "done"

  let loop_select (entry:lens) =
    generic_cond "select" "@select" "do" entry+ "done"

  let case (entry:lens) (entry_noeol:lens) =
       let pattern = [ label "@pattern" . sto_to_semicol . Sep.opt_space ]
    in let case_entry = [ label "@case_entry"
                       . Util.indent . pattern
                       . (Util.del_str "|" . Sep.opt_space . pattern)*
                       . Util.del_str ")" . eol
                       . entry* . entry_noeol?
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store (char+ | ("\"" . char+ . "\""))
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . (empty* . comment* . case_entry)*
        . empty* . comment*
        . keyword "esac" . comment_or_eol ]

  let subshell (entry:lens) =
    [ Util.indent . label "@subshell"
    . Util.del_str "{" . brace_eol
    . entry+
    . Util.indent . Util.del_str "}" . eol ]

  let function (entry:lens) (start_kw:string) (end_kw:string) =
    [ Util.indent . label "@function"
    . del /(function[ \t]+)?/ ""
    . store Rx.word . del /[ \t]*\(\)/ "()"
    . (comment_eol|brace_eol) . Util.del_str start_kw . brace_eol
    . entry+
    . Util.indent . Util.del_str end_kw . eol ]

  let rec rec_entry =
    let entry = comment | entry_eol | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry entry_noeol
      | function entry "{" "}"
      | function entry "(" ")"
      | subshell entry

  let lns_norec = del_empty* . (comment | entry_eol) *

  let lns = del_empty* . (comment | entry_eol | rec_entry) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n))

  let filter_sysconfig =
      sc_incl "*" .
      sc_excl "anaconda" .
      sc_excl "bootloader" .
      sc_excl "hw-uuid" .
      sc_excl "hwconf" .
      sc_excl "ip*tables" .
      sc_excl "ip*tables.save" .
      sc_excl "kernel" .
      sc_excl "*.pub" .
      sc_excl "sysstat.ioconf" .
      sc_excl "system-config-firewall" .
      sc_excl "system-config-securitylevel" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_excl "network/if-up.d/SuSEfirewall2" .
      sc_incl "network/providers/*" .
      sc_excl "network-scripts" .
      sc_incl "network-scripts/ifcfg-*" .
      sc_excl "rhn" .
      sc_incl "rhn/allowed-actions/*" .
      sc_excl "rhn/allowed-actions/script" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd" .
      sc_excl "SuSEfirewall2.d" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_excl "SuSEfirewall2.d/services/TEMPLATE" .
      sc_excl "*.systemd"

  let filter_default = incl "/etc/default/*"
                     . excl "/etc/default/grub_installdevice*"
                     . excl "/etc/default/rmt"
                     . excl "/etc/default/star"
                     . excl "/etc/default/whoopsie"
                     . incl "/etc/profile"
                     . incl "/etc/profile.d/*"
                     . excl "/etc/profile.d/*.csh"
                     . excl "/etc/profile.d/csh.local"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/conf.d/*"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"
                     . incl "/etc/firewalld/firewalld.conf"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/kamailio/kamctlrc"
                     . incl "/etc/lbu/lbu.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/os-release"
                     . incl "/etc/periodic.conf"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/rc.conf.d/*"
                     . incl "/etc/rc.conf.local"
                     . incl "/etc/selinux/config"
                     . incl "/etc/ucf.conf"
                     . incl "/etc/locale.conf"
                     . incl "/etc/vconsole.conf"
                     . incl "/etc/byobu/*"

  let filter = filter_sysconfig
             . filter_default
             . filter_misc
             . Util.stdexcl

  let xfm = transform lns filter

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)


Use regexp union instead of lens union in php.aug

Using a union of regexps is much faster than a union of lenses, since the
regular expressions that are constructed internally are much simpler.

(* PHP module for Augeas                      *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(*                                            *)

module PHP =

    autoload xfm

    (* PHP is a standard INI file *)
    let setting = "always_populate_raw_post_data"
                | "asp_tags"
                | "browscap"
                | "child_terminate"
                | "define_syslog_variables"
                | "doc_root"
                | "enable_dl"
                | "engine"
                | "expose_php"
                | "extension_dir"
                | "file_uploads"
		| "gpc_order"
                | "html_errors"
                | "implicit_flush"
                | "include_path"
                | "last_modified"
                | "memory_limit"
                | "open_basedir"
                | "post_max_size"
                | "precision"
                | "serialize_precision"
                | "short_open_tag"
                | "SMTP"
                | "smtp_port"
                | "track_errors"
                | "unserialize_callback_func"
                | "variables_order"
                | "xbithack"
                | "y2k_compliance"
                | /apc\.(cache_by_default|enabled|filters|gc_ttl|mmap_file_mask|num_files_hint|optimization|shm_segments|shm_size|slam_defense|ttl|user_entries_hint|user_ttl)/
                | /apd\.(dumpdir|statement_tracing)/
                | /arg_separator\.(input|output)/
                | /assert\.(active|bail|callback|quiet_eval|warning)/
                | /bcmath\.(scale)/
                | /blenc\.(key_file)/
                | /com\.(allow_dcom|autoregister_casesensitive|autoregister_typelib|autoregister_verbose|code_page|typelib_file)/
                | /crack\.(default_dictionary)/
                | /daffodildb\.(default_host|default_password|default_socket|default_user|port)/
                | /date\.(default_latitude|default_longitude|sunrise_zenith|sunset_zenith)/
                | /dba\.(default_handler)/
                | /dbx\.(colnames_case)/
                | /exif\.(decode_jis_intel|decode_jis_motorola|decode_unicode_intel|decode_unicode_motorola|encode_jis|encode_unicode)/
                | /fbsql\.(allow_persistent|autocommit|batchsize|default_database|default_database_password|default_host|default_password|default_user|generate_warnings|max_connections|max_links|max_persistent|max_results)/
                | /highlight\.(bg|comment|default|html|keyword|string)/
                | /hyperwave\.(allow_persistent|default_port)/
                | /ibase\.(allow_persistent|dateformat|default_charset|default_db|default_password|default_user|max_links|max_persistent|timeformat|timestampformat)/
                | /iconv\.(input_encoding|internal_encoding|output_encoding)/
                | /ifx\.(allow_persistent|blobinfile|byteasvarchar|charasvarchar|default_host|default_password|default_user|max_links|max_persistent|nullformat|textasvarchar)/
                | /ingres\.(allow_persistent|default_database|default_password|default_user|max_links|max_persistent)/
                | /ircg\.(control_user|keep_alive_interval|max_format_message_sets|shared_mem_size|work_dir)/
                | /ldap\.(max_links)/
                | /mail\.(force_extra_parameters)/
                | /mailparse\.(def_charset)/
                | /maxdb\.(default_db|default_host|default_pw|default_user|long_readlen)/
                | /mbstring\.(detect_order|encoding_translation|func_overload|http_input|http_output|internal_encoding|language|script_encoding|substitute_character)/
                | /mcrypt\.(algorithms_dir|modes_dir)/
                | /mime_magic\.(debug|magicfile)/
                | /mssql\.(allow_persistent|batchsize|compatability_mode|connect_timeout|datetimeconvert|max_links|max_persistent|max_procs|min_error_severity|min_message_severity|secure_connection|textlimit|textsize|timeout)/
                | /msql\.(allow_persistent|max_links|max_persistent)/
                | /mysql\.(allow_persistent|connect_timeout|default_host|default_password|default_port|default_socket|default_user|max_links|max_persistent|trace_mode)/
                | /mysqli\.(default_host|default_port|default_pw|default_socket|default_user|max_links|reconnect)/
                | /namazu\.(debugmode|lang|loggingmode|sortmethod|sortorder)/
                | /nsapi\.(read_timeout)/
                | /odbc\.(allow_persistent|check_persistent|defaultbinmode|defaultlrl|default_db|default_pw|default_user|max_links|max_persistent)/
                | /opendirectory\.(max_refs|separator)/
                | /pdo\.(global_value)/
                | /pfpro\.(defaulthost|defaultport|defaulttimeout|proxyaddress|proxylogon|proxypassword|proxyport)/
                | /pgsql\.(allow_persistent|auto_reset_persistent|ignore_notice|log_notice|max_links|max_persistent)/
                | /printer\.(default_printer)/
                | /session\.(auto_start|bug_compat_42|bug_compat_warn|cache_expire|cache_limiter|cookie_(domain|httponly|lifetime|path|secure)|entropy_file|entropy_length|gc_divisor|gc_maxlifetime|gc_probability|hash_bits_per_character|hash_function|name|referer_check|save_handler|save_path|serialize_handler|use_cookies|use_only_cookies|use_trans_sid)/
                | /session_pgsql\.(create_table|db|disable|failover_mode|gc_interval|keep_expired|sem_file_name|serializable|short_circuit|use_app_vars|vacuum_interval)/
                | /simple_cvs\.(authMethod|compressionLevel|cvsRoot|host|moduleName|userName|workingDir)/
                | /soap\.(wsdl_cache_dir|wsdl_cache_enabled|wsdl_cache_ttl)/
                | /sql\.(safe_mode)/
                | /sqlite\.(assoc_case)/
		| /sybase\.(allow_persistent|max_(persistent|links)|interface_file|min_(error|message)_severity|compatability_mode)/
                | /sybct\.(allow_persistent|deadlock_retry_count|hostname|login_timeout|max_links|max_persistent|min_client_severity|min_server_severity)/
                | /tidy\.(clean_output|default_config)/
                | /url_rewriter\.(tags)/
                | /valkyrie\.(auto_validate|config_path)/
                | /xmms\.(path|session)/
                | /yaz\.(keepalive|log_file|max_links)/
                | /zend\.(ze1_compatibility_mode)/
                | /zlib\.(output_compression|output_compression_level|output_handler)/
                | /allow_(call_time_pass_reference|url_fopen|url_include)/
                | /auto_(append_file|detect_line_endings|globals_jit|prepend_file)/
                | /default_(charset|mimetype|socket_timeout)/
		| /display(_startup)?_errors/
                | /disable_(classes|functions)/
                | /docref_(ext|root)/
                | /error_(append_string|log|prepend_string|reporting)/
                | /ignore_(repeated_errors|repeated_source|user_abort)/
                | /log_errors(_max_len)?/
                | /magic_quotes_(gpc|runtime|sybase)/
                | /max_(execution_time|input_time)/
                | /output_(buffering|handler)/
                | /realpath_(cache_size|cache_ttl)/
                | /register_(argc_argv|globals|long_arrays)/
                | /report_(memleaks|zend_debug)/
                | /safe_mode(_(allowed_env_vars|exec_dir|gid|include_dir|protected_env_vars))?/
                | /sendmail_(from|path)/
                | /upload_(max_filesize|tmp_dir)/
                | /user_(agent|dir)/
                | /xmlrpc_error(s|_number)/

	let entry  = IniFile.entry setting

	let record = IniFile.record "section" entry
	let lns    = IniFile.lns record

	let filter = (incl "/etc/php*/*/php.ini")
	           . Util.stdexcl

	let xfm = transform lns filter

(* PHP module for Augeas                      *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(*                                            *)

module PHP =

    autoload xfm

    (* PHP is a standard INI file *)
    let setting = IniFile.entry "always_populate_raw_post_data"
                | IniFile.entry "asp_tags"
                | IniFile.entry "browscap"
                | IniFile.entry "child_terminate"
                | IniFile.entry "define_syslog_variables"
                | IniFile.entry "doc_root"
                | IniFile.entry "enable_dl"
                | IniFile.entry "engine"
                | IniFile.entry "expose_php"
                | IniFile.entry "extension_dir"
                | IniFile.entry "file_uploads"
		| IniFile.entry "gpc_order"
                | IniFile.entry "html_errors"
                | IniFile.entry "implicit_flush"
                | IniFile.entry "include_path"
                | IniFile.entry "last_modified"
                | IniFile.entry "memory_limit"
                | IniFile.entry "open_basedir"
                | IniFile.entry "post_max_size"
                | IniFile.entry "precision"
                | IniFile.entry "serialize_precision"
                | IniFile.entry "short_open_tag"
                | IniFile.entry "SMTP"
                | IniFile.entry "smtp_port"
                | IniFile.entry "track_errors"
                | IniFile.entry "unserialize_callback_func"
                | IniFile.entry "variables_order"
                | IniFile.entry "xbithack"
                | IniFile.entry "y2k_compliance"
                | IniFile.entry /apc\.(cache_by_default|enabled|filters|gc_ttl|mmap_file_mask|num_files_hint|optimization|shm_segments|shm_size|slam_defense|ttl|user_entries_hint|user_ttl)/
                | IniFile.entry /apd\.(dumpdir|statement_tracing)/
                | IniFile.entry /arg_separator\.(input|output)/
                | IniFile.entry /assert\.(active|bail|callback|quiet_eval|warning)/
                | IniFile.entry /bcmath\.(scale)/
                | IniFile.entry /blenc\.(key_file)/
                | IniFile.entry /com\.(allow_dcom|autoregister_casesensitive|autoregister_typelib|autoregister_verbose|code_page|typelib_file)/
                | IniFile.entry /crack\.(default_dictionary)/
                | IniFile.entry /daffodildb\.(default_host|default_password|default_socket|default_user|port)/
                | IniFile.entry /date\.(default_latitude|default_longitude|sunrise_zenith|sunset_zenith)/
                | IniFile.entry /dba\.(default_handler)/
                | IniFile.entry /dbx\.(colnames_case)/
                | IniFile.entry /exif\.(decode_jis_intel|decode_jis_motorola|decode_unicode_intel|decode_unicode_motorola|encode_jis|encode_unicode)/
                | IniFile.entry /fbsql\.(allow_persistent|autocommit|batchsize|default_database|default_database_password|default_host|default_password|default_user|generate_warnings|max_connections|max_links|max_persistent|max_results)/
                | IniFile.entry /highlight\.(bg|comment|default|html|keyword|string)/
                | IniFile.entry /hyperwave\.(allow_persistent|default_port)/
                | IniFile.entry /ibase\.(allow_persistent|dateformat|default_charset|default_db|default_password|default_user|max_links|max_persistent|timeformat|timestampformat)/
                | IniFile.entry /iconv\.(input_encoding|internal_encoding|output_encoding)/
                | IniFile.entry /ifx\.(allow_persistent|blobinfile|byteasvarchar|charasvarchar|default_host|default_password|default_user|max_links|max_persistent|nullformat|textasvarchar)/
                | IniFile.entry /ingres\.(allow_persistent|default_database|default_password|default_user|max_links|max_persistent)/
                | IniFile.entry /ircg\.(control_user|keep_alive_interval|max_format_message_sets|shared_mem_size|work_dir)/
                | IniFile.entry /ldap\.(max_links)/
                | IniFile.entry /mail\.(force_extra_parameters)/
                | IniFile.entry /mailparse\.(def_charset)/
                | IniFile.entry /maxdb\.(default_db|default_host|default_pw|default_user|long_readlen)/
                | IniFile.entry /mbstring\.(detect_order|encoding_translation|func_overload|http_input|http_output|internal_encoding|language|script_encoding|substitute_character)/
                | IniFile.entry /mcrypt\.(algorithms_dir|modes_dir)/
                | IniFile.entry /mime_magic\.(debug|magicfile)/
                | IniFile.entry /mssql\.(allow_persistent|batchsize|compatability_mode|connect_timeout|datetimeconvert|max_links|max_persistent|max_procs|min_error_severity|min_message_severity|secure_connection|textlimit|textsize|timeout)/
                | IniFile.entry /msql\.(allow_persistent|max_links|max_persistent)/
                | IniFile.entry /mysql\.(allow_persistent|connect_timeout|default_host|default_password|default_port|default_socket|default_user|max_links|max_persistent|trace_mode)/
                | IniFile.entry /mysqli\.(default_host|default_port|default_pw|default_socket|default_user|max_links|reconnect)/
                | IniFile.entry /namazu\.(debugmode|lang|loggingmode|sortmethod|sortorder)/
                | IniFile.entry /nsapi\.(read_timeout)/
                | IniFile.entry /odbc\.(allow_persistent|check_persistent|defaultbinmode|defaultlrl|default_db|default_pw|default_user|max_links|max_persistent)/
                | IniFile.entry /opendirectory\.(max_refs|separator)/
                | IniFile.entry /pdo\.(global_value)/
                | IniFile.entry /pfpro\.(defaulthost|defaultport|defaulttimeout|proxyaddress|proxylogon|proxypassword|proxyport)/
                | IniFile.entry /pgsql\.(allow_persistent|auto_reset_persistent|ignore_notice|log_notice|max_links|max_persistent)/
                | IniFile.entry /printer\.(default_printer)/
                | IniFile.entry /session\.(auto_start|bug_compat_42|bug_compat_warn|cache_expire|cache_limiter|cookie_(domain|httponly|lifetime|path|secure)|entropy_file|entropy_length|gc_divisor|gc_maxlifetime|gc_probability|hash_bits_per_character|hash_function|name|referer_check|save_handler|save_path|serialize_handler|use_cookies|use_only_cookies|use_trans_sid)/
                | IniFile.entry /session_pgsql\.(create_table|db|disable|failover_mode|gc_interval|keep_expired|sem_file_name|serializable|short_circuit|use_app_vars|vacuum_interval)/
                | IniFile.entry /simple_cvs\.(authMethod|compressionLevel|cvsRoot|host|moduleName|userName|workingDir)/
                | IniFile.entry /soap\.(wsdl_cache_dir|wsdl_cache_enabled|wsdl_cache_ttl)/
                | IniFile.entry /sql\.(safe_mode)/
                | IniFile.entry /sqlite\.(assoc_case)/
		| IniFile.entry /sybase\.(allow_persistent|max_(persistent|links)|interface_file|min_(error|message)_severity|compatability_mode)/
                | IniFile.entry /sybct\.(allow_persistent|deadlock_retry_count|hostname|login_timeout|max_links|max_persistent|min_client_severity|min_server_severity)/
                | IniFile.entry /tidy\.(clean_output|default_config)/
                | IniFile.entry /url_rewriter\.(tags)/
                | IniFile.entry /valkyrie\.(auto_validate|config_path)/
                | IniFile.entry /xmms\.(path|session)/
                | IniFile.entry /yaz\.(keepalive|log_file|max_links)/
                | IniFile.entry /zend\.(ze1_compatibility_mode)/
                | IniFile.entry /zlib\.(output_compression|output_compression_level|output_handler)/
                | IniFile.entry /allow_(call_time_pass_reference|url_fopen|url_include)/
                | IniFile.entry /auto_(append_file|detect_line_endings|globals_jit|prepend_file)/
                | IniFile.entry /default_(charset|mimetype|socket_timeout)/
		| IniFile.entry /display(_startup)?_errors/
                | IniFile.entry /disable_(classes|functions)/
                | IniFile.entry /docref_(ext|root)/
                | IniFile.entry /error_(append_string|log|prepend_string|reporting)/
                | IniFile.entry /ignore_(repeated_errors|repeated_source|user_abort)/
                | IniFile.entry /log_errors(_max_len)?/
                | IniFile.entry /magic_quotes_(gpc|runtime|sybase)/
                | IniFile.entry /max_(execution_time|input_time)/
                | IniFile.entry /output_(buffering|handler)/
                | IniFile.entry /realpath_(cache_size|cache_ttl)/
                | IniFile.entry /register_(argc_argv|globals|long_arrays)/
                | IniFile.entry /report_(memleaks|zend_debug)/
                | IniFile.entry /safe_mode(_(allowed_env_vars|exec_dir|gid|include_dir|protected_env_vars))?/
                | IniFile.entry /sendmail_(from|path)/
                | IniFile.entry /upload_(max_filesize|tmp_dir)/
                | IniFile.entry /user_(agent|dir)/
                | IniFile.entry /xmlrpc_error(s|_number)/

	let record = IniFile.record "section" setting
	let lns    = IniFile.lns record

	let filter = (incl "/etc/php*/*/php.ini")
	           . Util.stdexcl

	let xfm = transform lns filter


nsswitch: Add action merge (#609)

nsswitch: Add action merge (#609)

(*
Module: Nsswitch
  Parses /etc/nsswitch.conf

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
  This lens tries to keep as close as possible to `man nsswitch.conf` where possible.

About: Licence
  This file is licensed under the LGPL v2+, like the rest of Augeas.

About: Lens Usage

About: Configuration files
  This lens applies to /etc/nsswitch.conf. See <filter>.
*)

module Nsswitch =
autoload xfm

(************************************************************************
 * Group:                 USEFUL PRIMITIVES
 *************************************************************************)

(* View: comment *)
let comment = Util.comment

(* View: empty *)
let empty = Util.empty

(* View: sep_colon
    The separator for database entries *)
let sep_colon = del /:[ \t]*/ ": "

(* View: database_kw
    The database specification like `passwd', `shadow', or `hosts' *)
let database_kw = Rx.word

(* View: service
    The service specification like `files', `db', or `nis' *)
let service = [ label "service" . store Rx.word ]

(* View: reaction
    The reaction on lookup result like `[NOTFOUND=return]'
    TODO: Use case-insensitive regexps when ticket #147 is fixed.
*)
let reaction =
  let status_kw = /[Ss][Uu][Cc][Cc][Ee][Ss][Ss]/
                | /[Nn][Oo][Tt][Ff][Oo][Uu][Nn][Dd]/
                | /[Uu][Nn][Aa][Vv][Aa][Ii][Ll]/
                | /[Tt][Rr][Yy][Aa][Gg][Aa][Ii][Nn]/
    in let action_kw = /[Rr][Ee][Tt][Uu][Rr][Nn]/
                     | /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/
                     | /[Mm][Ee][Rr][Gg][Ee]/
      in let negate = [ Util.del_str "!" . label "negate" ]
        in let reaction_entry = [ label "status" . negate?
                                . store status_kw
                                . Util.del_str "="
                                . [ label "action" . store action_kw ] ]
          in Util.del_str "["
             . [ label "reaction"
               . (Build.opt_list reaction_entry Sep.space) ]
             . Util.del_str "]"

(* View: database *)
let database =
    [ label "database" . store database_kw
       . sep_colon
       . (Build.opt_list
            (service|reaction)
            Sep.space)
       . Util.comment_or_eol ]

(* View: lns *)
let lns = ( empty | comment | database )*

(* Variable: filter *)
let filter = (incl "/etc/nsswitch.conf")

let xfm = transform lns filter

(*
Module: Nsswitch
  Parses /etc/nsswitch.conf

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
  This lens tries to keep as close as possible to `man nsswitch.conf` where possible.

About: Licence
  This file is licensed under the LGPL v2+, like the rest of Augeas.

About: Lens Usage

About: Configuration files
  This lens applies to /etc/nsswitch.conf. See <filter>.
*)

module Nsswitch =
autoload xfm

(************************************************************************
 * Group:                 USEFUL PRIMITIVES
 *************************************************************************)

(* View: comment *)
let comment = Util.comment

(* View: empty *)
let empty = Util.empty

(* View: sep_colon
    The separator for database entries *)
let sep_colon = del /:[ \t]*/ ": "

(* View: database_kw
    The database specification like `passwd', `shadow', or `hosts' *)
let database_kw = Rx.word

(* View: service
    The service specification like `files', `db', or `nis' *)
let service = [ label "service" . store Rx.word ]

(* View: reaction
    The reaction on lookup result like `[NOTFOUND=return]'
    TODO: Use case-insensitive regexps when ticket #147 is fixed.
*)
let reaction =
  let status_kw = /[Ss][Uu][Cc][Cc][Ee][Ss][Ss]/
                | /[Nn][Oo][Tt][Ff][Oo][Uu][Nn][Dd]/
                | /[Uu][Nn][Aa][Vv][Aa][Ii][Ll]/
                | /[Tt][Rr][Yy][Aa][Gg][Aa][Ii][Nn]/
    in let action_kw = /[Rr][Ee][Tt][Uu][Rr][Nn]/
                     | /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/
      in let negate = [ Util.del_str "!" . label "negate" ]
        in let reaction_entry = [ label "status" . negate?
                                . store status_kw
                                . Util.del_str "="
                                . [ label "action" . store action_kw ] ]
          in Util.del_str "["
             . [ label "reaction"
               . (Build.opt_list reaction_entry Sep.space) ]
             . Util.del_str "]"

(* View: database *)
let database =
    [ label "database" . store database_kw
       . sep_colon
       . (Build.opt_list
            (service|reaction)
            Sep.space)
       . Util.comment_or_eol ]

(* View: lns *)
let lns = ( empty | comment | database )*

(* Variable: filter *)
let filter = (incl "/etc/nsswitch.conf")

let xfm = transform lns filter


Added more pkinit_* options.

Added more pkinit_* options.

module Krb5 =

autoload xfm

let comment = Inifile.comment IniFile.comment_re "#"
let empty = Inifile.empty
let eol = Inifile.eol
let dels = Util.del_str

let indent = del /[ \t]*/ ""
let comma_or_space_sep = del /[ \t,]{1,}/ " "
let eq = del /[ \t]*=[ \t]*/ " = "
let eq_openbr = del /[ \t]*=[ \t\n]*\{[ \t]*\n/ " = {\n"
let closebr = del /[ \t]*\}/ "}"

(* These two regexps for realms and apps are not entirely true
   - strictly speaking, there's no requirement that a realm is all upper case
   and an application only uses lowercase. But it's what's used in practice.

   Without that distinction we couldn't distinguish between applications
   and realms in the [appdefaults] section.
*)

let realm_re = /[A-Z0-9][.a-zA-Z0-9-]*/
let realm_anycase_re = /[A-Za-z0-9][.a-zA-Z0-9-]*/
let app_re = /[a-z][a-zA-Z0-9_]*/
let name_re = /[.a-zA-Z0-9_-]+/

let value_br = store /[^;# \t\r\n{}]+/
let value = store /[^;# \t\r\n]+/
let entry (kw:regexp) (sep:lens) (value:lens) (comment:lens)
    = [ indent . key kw . sep . value . (comment|eol) ] | comment

let subsec_entry (kw:regexp) (sep:lens) (comment:lens)
    = ( entry kw sep value_br comment ) | empty

let simple_section (n:string) (k:regexp) =
  let title = Inifile.indented_title n in
  let entry = entry k eq value comment in
    Inifile.record title entry

let record (t:string) (e:lens) =
  let title = Inifile.indented_title t in
    Inifile.record title e

let v4_name_convert (subsec:lens) = [ indent . key "v4_name_convert" .
                        eq_openbr .  subsec* . closebr . eol ]

(*
  For the enctypes this appears to be a list of the valid entries:
       c4-hmac arcfour-hmac aes128-cts rc4-hmac
       arcfour-hmac-md5 des3-cbc-sha1 des-cbc-md5 des-cbc-crc
*)
let enctype_re = /[a-zA-Z0-9-]{3,}/
let enctypes = /permitted_enctypes|default_tgs_enctypes|default_tkt_enctypes/i

(* An #eol label prevents ambiguity between "k = v1 v2" and "k = v1\n k = v2" *)
let enctype_list (nr:regexp) (ns:string) =
  indent . del nr ns . eq
    . Build.opt_list [ label ns . store enctype_re ] comma_or_space_sep
    . (comment|eol) . [ label "#eol" ]

let libdefaults =
  let option = entry (name_re - ("v4_name_convert" |enctypes)) eq value comment in
  let enctype_lists = enctype_list /permitted_enctypes/i "permitted_enctypes"
                      | enctype_list /default_tgs_enctypes/i "default_tgs_enctypes"
                      | enctype_list /default_tkt_enctypes/i "default_tkt_enctypes" in
  let subsec = [ indent . key /host|plain/ . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  record "libdefaults" (option|enctype_lists|v4_name_convert subsec)

let login =
  let keys = /krb[45]_get_tickets|krb4_convert|krb_run_aklog/
    |/aklog_path|accept_passwd/ in
    simple_section "login" keys

let appdefaults =
  let option = entry (name_re - ("realm" | "application")) eq value_br comment in
  let realm = [ indent . label "realm" . store realm_re .
                  eq_openbr . (option|empty)* . closebr . eol ] in
  let app = [ indent . label "application" . store app_re .
                eq_openbr . (realm|option|empty)* . closebr . eol] in
    record "appdefaults" (option|realm|app)

let realms =
  let simple_option = /kdc|admin_server|database_module|default_domain/
      |/v4_realm|auth_to_local(_names)?|master_kdc|kpasswd_server/
      |/admin_server|ticket_lifetime|pkinit_(anchors|identities|identity|pool)/
      |/krb524_server/ in
  let subsec_option = /v4_instance_convert/ in
  let option = subsec_entry simple_option eq comment in
  let subsec = [ indent . key subsec_option . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  let v4subsec = [ indent . key /host|plain/ . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  let realm = [ indent . label "realm" . store realm_anycase_re .
                  eq_openbr . (option|subsec|(v4_name_convert v4subsec))* .
                  closebr . eol ] in
    record "realms" (realm|comment)

let domain_realm =
  simple_section "domain_realm" name_re

let logging =
  let keys = /kdc|admin_server|default/ in
  let xchg (m:regexp) (d:string) (l:string) =
    del m d . label l in
  let xchgs (m:string) (l:string) = xchg m m l in
  let dest =
    [ xchg /FILE[=:]/ "FILE=" "file" . value ]
    |[ xchgs "STDERR" "stderr" ]
    |[ xchgs "CONSOLE" "console" ]
    |[ xchgs "DEVICE=" "device" . value ]
    |[ xchgs "SYSLOG" "syslog" .
         ([ xchgs ":" "severity" . store /[A-Za-z0-9]+/ ].
          [ xchgs ":" "facility" . store /[A-Za-z0-9]+/ ]?)? ] in
  let entry = [ indent . key keys . eq . dest . (comment|eol) ] | comment in
    record "logging" entry

let capaths =
  let realm = [ indent . key realm_re .
                  eq_openbr .
                  (entry realm_re eq value_br comment)* . closebr . eol ] in
    record "capaths" (realm|comment)

let dbdefaults =
  let keys = /database_module|ldap_kerberos_container_dn|ldap_kdc_dn/
    |/ldap_kadmind_dn|ldap_service_password_file|ldap_servers/
    |/ldap_conns_per_server/ in
    simple_section "dbdefaults" keys

let dbmodules =
  let keys = /db_library|ldap_kerberos_container_dn|ldap_kdc_dn/
    |/ldap_kadmind_dn|ldap_service_password_file|ldap_servers/
    |/ldap_conns_per_server/ in
    simple_section "dbmodules" keys

(* This section is not documented in the krb5.conf manpage,
   but the Fermi example uses it. *)
let instance_mapping =
  let value = dels "\"" . store /[^;# \t\r\n{}]*/ . dels "\"" in
  let map_node = label "mapping" . store /[a-zA-Z0-9\/*]+/ in
  let mapping = [ indent . map_node . eq .
                    [ label "value" . value ] . (comment|eol) ] in
  let instance = [ indent . key name_re .
                     eq_openbr . (mapping|comment)* . closebr . eol ] in
    record "instancemapping" instance

let kdc =
  simple_section "kdc" /profile/

let pam =
  simple_section "pam" name_re

let includes = Build.key_value_line /include(dir)?/ Sep.space (store Rx.fspath)

let lns = (comment|empty|includes)* .
  (libdefaults|login|appdefaults|realms|domain_realm
  |logging|capaths|dbdefaults|dbmodules|instance_mapping|kdc|pam)*

let filter = (incl "/etc/krb5.conf.d/*.conf")
           . (incl "/etc/krb5.conf")

let xfm = transform lns filter

module Krb5 =

autoload xfm

let comment = Inifile.comment IniFile.comment_re "#"
let empty = Inifile.empty
let eol = Inifile.eol
let dels = Util.del_str

let indent = del /[ \t]*/ ""
let comma_or_space_sep = del /[ \t,]{1,}/ " "
let eq = del /[ \t]*=[ \t]*/ " = "
let eq_openbr = del /[ \t]*=[ \t\n]*\{[ \t]*\n/ " = {\n"
let closebr = del /[ \t]*\}/ "}"

(* These two regexps for realms and apps are not entirely true
   - strictly speaking, there's no requirement that a realm is all upper case
   and an application only uses lowercase. But it's what's used in practice.

   Without that distinction we couldn't distinguish between applications
   and realms in the [appdefaults] section.
*)

let realm_re = /[A-Z0-9][.a-zA-Z0-9-]*/
let realm_anycase_re = /[A-Za-z0-9][.a-zA-Z0-9-]*/
let app_re = /[a-z][a-zA-Z0-9_]*/
let name_re = /[.a-zA-Z0-9_-]+/

let value_br = store /[^;# \t\r\n{}]+/
let value = store /[^;# \t\r\n]+/
let entry (kw:regexp) (sep:lens) (value:lens) (comment:lens)
    = [ indent . key kw . sep . value . (comment|eol) ] | comment

let subsec_entry (kw:regexp) (sep:lens) (comment:lens)
    = ( entry kw sep value_br comment ) | empty

let simple_section (n:string) (k:regexp) =
  let title = Inifile.indented_title n in
  let entry = entry k eq value comment in
    Inifile.record title entry

let record (t:string) (e:lens) =
  let title = Inifile.indented_title t in
    Inifile.record title e

let v4_name_convert (subsec:lens) = [ indent . key "v4_name_convert" .
                        eq_openbr .  subsec* . closebr . eol ]

(*
  For the enctypes this appears to be a list of the valid entries:
       c4-hmac arcfour-hmac aes128-cts rc4-hmac
       arcfour-hmac-md5 des3-cbc-sha1 des-cbc-md5 des-cbc-crc
*)
let enctype_re = /[a-zA-Z0-9-]{3,}/
let enctypes = /permitted_enctypes|default_tgs_enctypes|default_tkt_enctypes/i

(* An #eol label prevents ambiguity between "k = v1 v2" and "k = v1\n k = v2" *)
let enctype_list (nr:regexp) (ns:string) =
  indent . del nr ns . eq
    . Build.opt_list [ label ns . store enctype_re ] comma_or_space_sep
    . (comment|eol) . [ label "#eol" ]

let libdefaults =
  let option = entry (name_re - ("v4_name_convert" |enctypes)) eq value comment in
  let enctype_lists = enctype_list /permitted_enctypes/i "permitted_enctypes"
                      | enctype_list /default_tgs_enctypes/i "default_tgs_enctypes"
                      | enctype_list /default_tkt_enctypes/i "default_tkt_enctypes" in
  let subsec = [ indent . key /host|plain/ . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  record "libdefaults" (option|enctype_lists|v4_name_convert subsec)

let login =
  let keys = /krb[45]_get_tickets|krb4_convert|krb_run_aklog/
    |/aklog_path|accept_passwd/ in
    simple_section "login" keys

let appdefaults =
  let option = entry (name_re - ("realm" | "application")) eq value_br comment in
  let realm = [ indent . label "realm" . store realm_re .
                  eq_openbr . (option|empty)* . closebr . eol ] in
  let app = [ indent . label "application" . store app_re .
                eq_openbr . (realm|option|empty)* . closebr . eol] in
    record "appdefaults" (option|realm|app)

let realms =
  let simple_option = /kdc|admin_server|database_module|default_domain/
      |/v4_realm|auth_to_local(_names)?|master_kdc|kpasswd_server/
      |/admin_server|ticket_lifetime|pkinit_anchors|krb524_server/ in
  let subsec_option = /v4_instance_convert/ in
  let option = subsec_entry simple_option eq comment in
  let subsec = [ indent . key subsec_option . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  let v4subsec = [ indent . key /host|plain/ . eq_openbr .
                   (subsec_entry name_re eq comment)* . closebr . eol ] in
  let realm = [ indent . label "realm" . store realm_anycase_re .
                  eq_openbr . (option|subsec|(v4_name_convert v4subsec))* .
                  closebr . eol ] in
    record "realms" (realm|comment)

let domain_realm =
  simple_section "domain_realm" name_re

let logging =
  let keys = /kdc|admin_server|default/ in
  let xchg (m:regexp) (d:string) (l:string) =
    del m d . label l in
  let xchgs (m:string) (l:string) = xchg m m l in
  let dest =
    [ xchg /FILE[=:]/ "FILE=" "file" . value ]
    |[ xchgs "STDERR" "stderr" ]
    |[ xchgs "CONSOLE" "console" ]
    |[ xchgs "DEVICE=" "device" . value ]
    |[ xchgs "SYSLOG" "syslog" .
         ([ xchgs ":" "severity" . store /[A-Za-z0-9]+/ ].
          [ xchgs ":" "facility" . store /[A-Za-z0-9]+/ ]?)? ] in
  let entry = [ indent . key keys . eq . dest . (comment|eol) ] | comment in
    record "logging" entry

let capaths =
  let realm = [ indent . key realm_re .
                  eq_openbr .
                  (entry realm_re eq value_br comment)* . closebr . eol ] in
    record "capaths" (realm|comment)

let dbdefaults =
  let keys = /database_module|ldap_kerberos_container_dn|ldap_kdc_dn/
    |/ldap_kadmind_dn|ldap_service_password_file|ldap_servers/
    |/ldap_conns_per_server/ in
    simple_section "dbdefaults" keys

let dbmodules =
  let keys = /db_library|ldap_kerberos_container_dn|ldap_kdc_dn/
    |/ldap_kadmind_dn|ldap_service_password_file|ldap_servers/
    |/ldap_conns_per_server/ in
    simple_section "dbmodules" keys

(* This section is not documented in the krb5.conf manpage,
   but the Fermi example uses it. *)
let instance_mapping =
  let value = dels "\"" . store /[^;# \t\r\n{}]*/ . dels "\"" in
  let map_node = label "mapping" . store /[a-zA-Z0-9\/*]+/ in
  let mapping = [ indent . map_node . eq .
                    [ label "value" . value ] . (comment|eol) ] in
  let instance = [ indent . key name_re .
                     eq_openbr . (mapping|comment)* . closebr . eol ] in
    record "instancemapping" instance

let kdc =
  simple_section "kdc" /profile/

let pam =
  simple_section "pam" name_re

let includes = Build.key_value_line /include(dir)?/ Sep.space (store Rx.fspath)

let lns = (comment|empty|includes)* .
  (libdefaults|login|appdefaults|realms|domain_realm
  |logging|capaths|dbdefaults|dbmodules|instance_mapping|kdc|pam)*

let filter = (incl "/etc/krb5.conf.d/*.conf")
           . (incl "/etc/krb5.conf")

let xfm = transform lns filter


Support \r in comments in util.aug

Support \r in comments in util.aug

(*
Module: Util
  Generic module providing useful primitives

Author: David Lutterkort

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Util =

(*
Variable: del_str
  Delete a string and default to it

  Parameters:
     s:string - the string to delete and default to
*)
  let del_str (s:string) = del s s

(*
Variable: del_ws
  Delete mandatory whitespace
*)
  let del_ws = del /[ \t]+/

(*
Variable: del_ws_spc
  Delete mandatory whitespace, default to single space
*)
  let del_ws_spc = del_ws " "

(*
Variable: del_ws_tab
  Delete mandatory whitespace, default to single tab
*)
  let del_ws_tab = del_ws "\t"

(*
Variable: del_opt_ws
  Delete optional whitespace
*)
  let del_opt_ws = del /[ \t]*/

(*
Variable: eol
  Delete end of line, including optional trailing whitespace
*)
  let eol = del /[ \t]*\n/ "\n"

(*
Variable: doseol
  Delete end of line with optional carriage return,
  including optional trailing whitespace
*)
  let doseol = del /[ \t]*\r?\n/ "\n"

(*
Variable: indent
  Delete indentation, including leading whitespace
*)
  let indent = del /[ \t]*/ ""

(* Group: Comment
     This is a general definition of comment
     It allows indentation for comments, removes the leading and trailing spaces
     of comments and stores them in nodes, except for empty comments which are
     ignored together with empty lines

View: comment_generic
  Map comments and set default comment sign
*)

  let comment_generic (r:regexp) (d:string) =
    [ label "#comment" . del r d
        . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . doseol ]

(* View: comment
  Map comments into "#comment" nodes
*)
  let comment = comment_generic /[ \t]*#[ \t]*/ "# "

(* View: comment_noindent
  Map comments into "#comment" nodes, without indentation
*)
  let comment_noindent = comment_generic /#[ \t]*/ "# "

(* View: comment_eol
  Map eol comments into "#comment" nodes
  Add a space before # for end of line comments
*)
  let comment_eol = comment_generic /[ \t]*#[ \t]*/ " # "

(* View: comment_or_eol
    A <comment_eol> or <eol>, with an optional empty comment *)
 let comment_or_eol = comment_eol | (del /[ \t]*(#[ \t]*)?\n/ "\n")

(* View: comment_multiline
    A C-style multiline comment *)
  let comment_multiline =
     let mline_re = (/[^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n]/ - /.*\*\/.*/) in
     let mline = [ seq "mline"
                 . del /[ \t\r\n]*/ "\n"
                 . store mline_re ] in
     [ label "#mcomment" . del /[ \t]*\/\*/ "/*"
       . counter "mline"
       . mline . (eol . mline)*
       . del /[ \t\r\n]*\*\/[ \t]*\r?\n/ "\n*/\n" ]

(* View: comment_c_style
    A comment line, C-style *)
  let comment_c_style =
    comment_generic /[ \t]*\/\/[ \t]*/ "// "

(* View: empty_generic
  A generic definition of <empty>
  Map empty lines, including empty comments *)
  let empty_generic (r:regexp) =
    [ del r "" . del_str "\n" ]

(* View: empty
  Map empty lines, including empty comments *)
  let empty = empty_generic /[ \t]*#?[ \t]*/

(* View: empty_c_style
  Map empty lines, including C-style empty comment *)
  let empty_c_style =
    empty_generic /[ \t]*((\/\/)|(\/\*[ \t]*\*\/))?[ \t]*/

(* View: empty_dos *)
  let empty_dos =
    [ del /[ \t]*#?[ \t]*/ "" . del /\r?\n/ "\n" ]

(* View: Split *)
(* Split (SEP . ELT)* into an array-like tree where each match for ELT *)
(* appears in a separate subtree. The labels for the subtrees are      *)
(* consecutive numbers, starting at 0                                  *)
  let split (elt:lens) (sep:lens) =
    let sym = gensym "split" in
    counter sym . ( [ seq sym . sep . elt ] ) *

(* View: delim *)
  let delim (op:string) = del (/[ \t]*/ . op . /[ \t]*/)
                              (" " . op . " ")

(* Group: Exclusions

Variable: stdexcl
  Exclusion for files that are commonly not wanted/needed
*)
  let stdexcl = (excl "*~") .
    (excl "*.rpmnew") .
    (excl "*.rpmsave") .
    (excl "*.dpkg-old") .
    (excl "*.dpkg-new") .
    (excl "*.dpkg-bak") .
    (excl "*.dpkg-dist") .
    (excl "*.augsave") .
    (excl "*.augnew")

(*
Module: Util
  Generic module providing useful primitives

Author: David Lutterkort

About: License
  This file is licensed under the LGPLv2+, like the rest of Augeas.
*)

module Util =

(*
Variable: del_str
  Delete a string and default to it

  Parameters:
     s:string - the string to delete and default to
*)
  let del_str (s:string) = del s s

(*
Variable: del_ws
  Delete mandatory whitespace
*)
  let del_ws = del /[ \t]+/

(*
Variable: del_ws_spc
  Delete mandatory whitespace, default to single space
*)
  let del_ws_spc = del_ws " "

(*
Variable: del_ws_tab
  Delete mandatory whitespace, default to single tab
*)
  let del_ws_tab = del_ws "\t"

(*
Variable: del_opt_ws
  Delete optional whitespace
*)
  let del_opt_ws = del /[ \t]*/

(*
Variable: eol
  Delete end of line, including optional trailing whitespace
*)
  let eol = del /[ \t]*\n/ "\n"

(*
Variable: doseol
  Delete end of line with optional carriage return,
  including optional trailing whitespace
*)
  let doseol = del /[ \t]*\r?\n/ "\n"

(*
Variable: indent
  Delete indentation, including leading whitespace
*)
  let indent = del /[ \t]*/ ""

(* Group: Comment
     This is a general definition of comment
     It allows indentation for comments, removes the leading and trailing spaces
     of comments and stores them in nodes, except for empty comments which are
     ignored together with empty lines

View: comment_generic
  Map comments and set default comment sign
*)

  let comment_generic (r:regexp) (d:string) =
    [ label "#comment" . del r d
        . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ]

(* View: comment
  Map comments into "#comment" nodes
*)
  let comment = comment_generic /[ \t]*#[ \t]*/ "# "

(* View: comment_noindent
  Map comments into "#comment" nodes, without indentation
*)
  let comment_noindent = comment_generic /#[ \t]*/ "# "

(* View: comment_eol
  Map eol comments into "#comment" nodes
  Add a space before # for end of line comments
*)
  let comment_eol = comment_generic /[ \t]*#[ \t]*/ " # "

(* View: comment_or_eol
    A <comment_eol> or <eol>, with an optional empty comment *)
 let comment_or_eol = comment_eol | (del /[ \t]*(#[ \t]*)?\n/ "\n")

(* View: comment_multiline
    A C-style multiline comment *)
  let comment_multiline =
     let mline_re = (/[^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n]/ - /.*\*\/.*/) in
     let mline = [ seq "mline"
                 . del /[ \t\r\n]*/ "\n"
                 . store mline_re ] in
     [ label "#mcomment" . del /[ \t]*\/\*/ "/*"
       . counter "mline"
       . mline . (eol . mline)*
       . del /[ \t\r\n]*\*\/[ \t]*\r?\n/ "\n*/\n" ]

(* View: comment_c_style
    A comment line, C-style *)
  let comment_c_style =
    comment_generic /[ \t]*\/\/[ \t]*/ "// "

(* View: empty_generic
  A generic definition of <empty>
  Map empty lines, including empty comments *)
  let empty_generic (r:regexp) =
    [ del r "" . del_str "\n" ]

(* View: empty
  Map empty lines, including empty comments *)
  let empty = empty_generic /[ \t]*#?[ \t]*/

(* View: empty_c_style
  Map empty lines, including C-style empty comment *)
  let empty_c_style =
    empty_generic /[ \t]*((\/\/)|(\/\*[ \t]*\*\/))?[ \t]*/

(* View: Split *)
(* Split (SEP . ELT)* into an array-like tree where each match for ELT *)
(* appears in a separate subtree. The labels for the subtrees are      *)
(* consecutive numbers, starting at 0                                  *)
  let split (elt:lens) (sep:lens) =
    let sym = gensym "split" in
    counter sym . ( [ seq sym . sep . elt ] ) *

(* View: delim *)
  let delim (op:string) = del (/[ \t]*/ . op . /[ \t]*/)
                              (" " . op . " ")

(* Group: Exclusions

Variable: stdexcl
  Exclusion for files that are commonly not wanted/needed
*)
  let stdexcl = (excl "*~") .
    (excl "*.rpmnew") .
    (excl "*.rpmsave") .
    (excl "*.dpkg-old") .
    (excl "*.dpkg-new") .
    (excl "*.dpkg-bak") .
    (excl "*.dpkg-dist") .
    (excl "*.augsave") .
    (excl "*.augnew")


qemu: group swtpm entry in augeas file

qemu: group swtpm entry in augeas file

They are meant to be together.

Signed-off-by: Ján Tomko <4cab11cfb98d3c937327354a78eb07dbb6ee2bc6@redhat.com>
Reviewed-by: John Ferlan <87558058f6f829e5ec976c8ef960720af4ff9c7d@redhat.com>

(* /etc/libvirt/qemu.conf *)

module Libvirtd_qemu =
   autoload xfm

   let eol   = del /[ \t]*\n/ "\n"
   let value_sep   = del /[ \t]*=[ \t]*/  " = "
   let indent = del /[ \t]*/ ""

   let array_sep  = del /,[ \t\n]*/ ", "
   let array_start = del /\[[ \t\n]*/ "[ "
   let array_end = del /\]/ "]"

   let str_val = del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\""
   let bool_val = store /0|1/
   let int_val = store /[0-9]+/
   let str_array_element = [ seq "el" . str_val ] . del /[ \t\n]*/ ""
   let str_array_val = counter "el" . array_start . ( str_array_element . ( array_sep . str_array_element ) * ) ? . array_end

   let str_entry       (kw:string) = [ key kw . value_sep . str_val ]
   let bool_entry      (kw:string) = [ key kw . value_sep . bool_val ]
   let int_entry       (kw:string) = [ key kw . value_sep . int_val ]
   let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ]

   let unlimited_val =  del /\"/ "\"" . store /unlimited/ . del /\"/ "\""
   let limits_entry (kw:string) = [ key kw . value_sep . unlimited_val ] |  [ key kw . value_sep . int_val ]

   (* Config entry grouped by function - same order as example config *)
   let default_tls_entry = str_entry "default_tls_x509_cert_dir"
                 | bool_entry "default_tls_x509_verify"
                 | str_entry "default_tls_x509_secret_uuid"

   let vnc_entry = str_entry "vnc_listen"
                 | bool_entry "vnc_auto_unix_socket"
                 | bool_entry "vnc_tls"
                 | str_entry "vnc_tls_x509_cert_dir"
                 | bool_entry "vnc_tls_x509_verify"
                 | str_entry "vnc_password"
                 | bool_entry "vnc_sasl"
                 | str_entry "vnc_sasl_dir"
                 | bool_entry "vnc_allow_host_audio"

   let spice_entry = str_entry "spice_listen"
                 | bool_entry "spice_tls"
                 | str_entry  "spice_tls_x509_cert_dir"
                 | bool_entry "spice_auto_unix_socket"
                 | str_entry "spice_password"
                 | bool_entry "spice_sasl"
                 | str_entry "spice_sasl_dir"

   let chardev_entry = bool_entry "chardev_tls"
                 | str_entry "chardev_tls_x509_cert_dir"
                 | bool_entry "chardev_tls_x509_verify"
                 | str_entry "chardev_tls_x509_secret_uuid"

   let migrate_entry = str_entry "migrate_tls_x509_cert_dir"
                 | bool_entry "migrate_tls_x509_verify"
                 | str_entry "migrate_tls_x509_secret_uuid"

   let nogfx_entry = bool_entry "nographics_allow_host_audio"

   let remote_display_entry = int_entry "remote_display_port_min"
                 | int_entry "remote_display_port_max"
                 | int_entry "remote_websocket_port_min"
                 | int_entry "remote_websocket_port_max"

   let security_entry = str_entry "security_driver"
                 | bool_entry "security_default_confined"
                 | bool_entry "security_require_confined"
                 | str_entry "user"
                 | str_entry "group"
                 | bool_entry "dynamic_ownership"
                 | str_array_entry "cgroup_controllers"
                 | str_array_entry "cgroup_device_acl"
                 | int_entry "seccomp_sandbox"
                 | str_array_entry "namespaces"

   let save_entry = str_entry "save_image_format"
                 | str_entry "dump_image_format"
                 | str_entry "snapshot_image_format"
                 | str_entry "auto_dump_path"
                 | bool_entry "auto_dump_bypass_cache"
                 | bool_entry "auto_start_bypass_cache"

   let process_entry = str_entry "hugetlbfs_mount"
                 | bool_entry "clear_emulator_capabilities"
                 | str_entry "bridge_helper"
                 | str_entry "pr_helper"
                 | bool_entry "set_process_name"
                 | int_entry "max_processes"
                 | int_entry "max_files"
                 | limits_entry "max_core"
                 | bool_entry "dump_guest_core"
                 | str_entry "stdio_handler"

   let device_entry = bool_entry "mac_filter"
                 | bool_entry "relaxed_acs_check"
                 | bool_entry "allow_disk_format_probing"
                 | str_entry "lock_manager"

   let rpc_entry = int_entry "max_queued"
                 | int_entry "keepalive_interval"
                 | int_entry "keepalive_count"

   let network_entry = str_entry "migration_address"
                 | int_entry "migration_port_min"
                 | int_entry "migration_port_max"
                 | str_entry "migration_host"

   let log_entry = bool_entry "log_timestamp"

   let nvram_entry = str_array_entry "nvram"

   let gluster_debug_level_entry = int_entry "gluster_debug_level"

   let memory_entry = str_entry "memory_backing_dir"

   let vxhs_entry = bool_entry "vxhs_tls"
                 | str_entry "vxhs_tls_x509_cert_dir"

   let nbd_entry = bool_entry "nbd_tls"
                | str_entry "nbd_tls_x509_cert_dir"

   let swtpm_entry = str_entry "swtpm_user"
                | str_entry "swtpm_group"

   (* Each entry in the config is one of the following ... *)
   let entry = default_tls_entry
             | vnc_entry
             | spice_entry
             | chardev_entry
             | migrate_entry
             | nogfx_entry
             | remote_display_entry
             | security_entry
             | save_entry
             | process_entry
             | device_entry
             | rpc_entry
             | network_entry
             | log_entry
             | nvram_entry
             | gluster_debug_level_entry
             | memory_entry
             | vxhs_entry
             | nbd_entry
             | swtpm_entry

   let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
   let empty = [ label "#empty" . eol ]

   let record = indent . entry . eol

   let lns = ( record | comment | empty ) *

   let filter = incl "/etc/libvirt/qemu.conf"
              . Util.stdexcl

   let xfm = transform lns filter

(* /etc/libvirt/qemu.conf *)

module Libvirtd_qemu =
   autoload xfm

   let eol   = del /[ \t]*\n/ "\n"
   let value_sep   = del /[ \t]*=[ \t]*/  " = "
   let indent = del /[ \t]*/ ""

   let array_sep  = del /,[ \t\n]*/ ", "
   let array_start = del /\[[ \t\n]*/ "[ "
   let array_end = del /\]/ "]"

   let str_val = del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\""
   let bool_val = store /0|1/
   let int_val = store /[0-9]+/
   let str_array_element = [ seq "el" . str_val ] . del /[ \t\n]*/ ""
   let str_array_val = counter "el" . array_start . ( str_array_element . ( array_sep . str_array_element ) * ) ? . array_end

   let str_entry       (kw:string) = [ key kw . value_sep . str_val ]
   let bool_entry      (kw:string) = [ key kw . value_sep . bool_val ]
   let int_entry       (kw:string) = [ key kw . value_sep . int_val ]
   let str_array_entry (kw:string) = [ key kw . value_sep . str_array_val ]

   let unlimited_val =  del /\"/ "\"" . store /unlimited/ . del /\"/ "\""
   let limits_entry (kw:string) = [ key kw . value_sep . unlimited_val ] |  [ key kw . value_sep . int_val ]

   (* Config entry grouped by function - same order as example config *)
   let default_tls_entry = str_entry "default_tls_x509_cert_dir"
                 | bool_entry "default_tls_x509_verify"
                 | str_entry "default_tls_x509_secret_uuid"

   let vnc_entry = str_entry "vnc_listen"
                 | bool_entry "vnc_auto_unix_socket"
                 | bool_entry "vnc_tls"
                 | str_entry "vnc_tls_x509_cert_dir"
                 | bool_entry "vnc_tls_x509_verify"
                 | str_entry "vnc_password"
                 | bool_entry "vnc_sasl"
                 | str_entry "vnc_sasl_dir"
                 | bool_entry "vnc_allow_host_audio"

   let spice_entry = str_entry "spice_listen"
                 | bool_entry "spice_tls"
                 | str_entry  "spice_tls_x509_cert_dir"
                 | bool_entry "spice_auto_unix_socket"
                 | str_entry "spice_password"
                 | bool_entry "spice_sasl"
                 | str_entry "spice_sasl_dir"

   let chardev_entry = bool_entry "chardev_tls"
                 | str_entry "chardev_tls_x509_cert_dir"
                 | bool_entry "chardev_tls_x509_verify"
                 | str_entry "chardev_tls_x509_secret_uuid"

   let migrate_entry = str_entry "migrate_tls_x509_cert_dir"
                 | bool_entry "migrate_tls_x509_verify"
                 | str_entry "migrate_tls_x509_secret_uuid"

   let nogfx_entry = bool_entry "nographics_allow_host_audio"

   let remote_display_entry = int_entry "remote_display_port_min"
                 | int_entry "remote_display_port_max"
                 | int_entry "remote_websocket_port_min"
                 | int_entry "remote_websocket_port_max"

   let security_entry = str_entry "security_driver"
                 | bool_entry "security_default_confined"
                 | bool_entry "security_require_confined"
                 | str_entry "user"
                 | str_entry "group"
                 | bool_entry "dynamic_ownership"
                 | str_array_entry "cgroup_controllers"
                 | str_array_entry "cgroup_device_acl"
                 | int_entry "seccomp_sandbox"
                 | str_array_entry "namespaces"

   let save_entry = str_entry "save_image_format"
                 | str_entry "dump_image_format"
                 | str_entry "snapshot_image_format"
                 | str_entry "auto_dump_path"
                 | bool_entry "auto_dump_bypass_cache"
                 | bool_entry "auto_start_bypass_cache"

   let process_entry = str_entry "hugetlbfs_mount"
                 | bool_entry "clear_emulator_capabilities"
                 | str_entry "bridge_helper"
                 | str_entry "pr_helper"
                 | bool_entry "set_process_name"
                 | int_entry "max_processes"
                 | int_entry "max_files"
                 | limits_entry "max_core"
                 | bool_entry "dump_guest_core"
                 | str_entry "stdio_handler"

   let device_entry = bool_entry "mac_filter"
                 | bool_entry "relaxed_acs_check"
                 | bool_entry "allow_disk_format_probing"
                 | str_entry "lock_manager"

   let rpc_entry = int_entry "max_queued"
                 | int_entry "keepalive_interval"
                 | int_entry "keepalive_count"

   let network_entry = str_entry "migration_address"
                 | int_entry "migration_port_min"
                 | int_entry "migration_port_max"
                 | str_entry "migration_host"

   let log_entry = bool_entry "log_timestamp"

   let nvram_entry = str_array_entry "nvram"

   let gluster_debug_level_entry = int_entry "gluster_debug_level"

   let memory_entry = str_entry "memory_backing_dir"

   let vxhs_entry = bool_entry "vxhs_tls"
                 | str_entry "vxhs_tls_x509_cert_dir"

   let nbd_entry = bool_entry "nbd_tls"
                | str_entry "nbd_tls_x509_cert_dir"

   let swtpm_user_entry = str_entry "swtpm_user"
   let swtpm_group_entry = str_entry "swtpm_group"

   (* Each entry in the config is one of the following ... *)
   let entry = default_tls_entry
             | vnc_entry
             | spice_entry
             | chardev_entry
             | migrate_entry
             | nogfx_entry
             | remote_display_entry
             | security_entry
             | save_entry
             | process_entry
             | device_entry
             | rpc_entry
             | network_entry
             | log_entry
             | nvram_entry
             | gluster_debug_level_entry
             | memory_entry
             | vxhs_entry
             | nbd_entry
             | swtpm_user_entry
             | swtpm_group_entry

   let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
   let empty = [ label "#empty" . eol ]

   let record = indent . entry . eol

   let lns = ( record | comment | empty ) *

   let filter = incl "/etc/libvirt/qemu.conf"
              . Util.stdexcl

   let xfm = transform lns filter


Grub: add support for 'serial' and 'terminal'

Patch by Sean E. Millichamp

module Grub =
  autoload xfm

    (* This only covers the most basic grub directives. Needs to be *)
    (* expanded to cover more (and more esoteric) directives        *)
    (* It is good enough to handle the grub.conf on my Fedora 8 box *)

    let value_to_eol = store /[^= \t][^\n]*/
    let eol = Util.del_str "\n"
    let del_to_eol = del /[^\n]*/ ""
    let value_sep (dflt:string) = del /[ \t]*[ \t=][ \t]*/ dflt

    let kw_arg (kw:string) (indent:string) (dflt_sep:string) =
      [ Util.del_opt_ws indent . key kw . value_sep dflt_sep
          . value_to_eol . eol ]

    let kw_boot_arg (kw:string) = kw_arg kw "\t" " "
    let kw_menu_arg (kw:string) = kw_arg kw "" "="

    let kw_pres (kw:string) = [ key kw . del_to_eol . eol ]

    let menu_setting = kw_menu_arg "default"
                     | kw_menu_arg "fallback"
                     | kw_pres "hiddenmenu"
                     | kw_menu_arg "timeout"
                     | kw_menu_arg "splashimage"
                     | kw_menu_arg "serial"
                     | kw_menu_arg "terminal"

    let title = del /title[ \t]+/ "title " . value_to_eol . eol

    let module_lines = [ label "modules" .
                            Util.del_ws "\t" .
                             Util.del_str "module" . Util.del_ws_spc
                             . value_to_eol . eol ]

    let boot_setting = kw_boot_arg "root"
                     | kw_boot_arg "kernel"
                     | kw_boot_arg "initrd"
                     | kw_pres "quiet"  (* Seems to be a Ubuntu extension *)
                     | module_lines

    let boot = [ label "title" . title . boot_setting* ]

    let comment = [ del /(#.*|[ \t]*)\n/ "#\n" ]

    let lns = (comment | menu_setting | boot)*
    let xfm = transform lns (incl "/etc/grub.conf")

module Grub =
  autoload xfm

    (* This only covers the most basic grub directives. Needs to be *)
    (* expanded to cover more (and more esoteric) directives        *)
    (* It is good enough to handle the grub.conf on my Fedora 8 box *)

    let value_to_eol = store /[^= \t][^\n]*/
    let eol = Util.del_str "\n"
    let del_to_eol = del /[^\n]*/ ""
    let value_sep (dflt:string) = del /[ \t]*[ \t=][ \t]*/ dflt

    let kw_arg (kw:string) (indent:string) (dflt_sep:string) =
      [ Util.del_opt_ws indent . key kw . value_sep dflt_sep
          . value_to_eol . eol ]

    let kw_boot_arg (kw:string) = kw_arg kw "\t" " "
    let kw_menu_arg (kw:string) = kw_arg kw "" "="

    let kw_pres (kw:string) = [ key kw . del_to_eol . eol ]

    let menu_setting = kw_menu_arg "default"
                     | kw_menu_arg "fallback"
                     | kw_pres "hiddenmenu"
                     | kw_menu_arg "timeout"
                     | kw_menu_arg "splashimage"

    let title = del /title[ \t]+/ "title " . value_to_eol . eol

    let module_lines = [ label "modules" .
                            Util.del_ws "\t" .
                             Util.del_str "module" . Util.del_ws_spc
                             . value_to_eol . eol ]

    let boot_setting = kw_boot_arg "root"
                     | kw_boot_arg "kernel"
                     | kw_boot_arg "initrd"
                     | kw_pres "quiet"  (* Seems to be a Ubuntu extension *)
                     | module_lines

    let boot = [ label "title" . title . boot_setting* ]

    let comment = [ del /(#.*|[ \t]*)\n/ "#\n" ]

    let lns = (comment | menu_setting | boot)*
    let xfm = transform lns (incl "/etc/grub.conf")


Allow parsing of options with equal sign (#587)

Ssh: Options in sshd_config can be specified using space, tab or equal sign.
They all have the same effect.

(*
Module: Sshd
  Parses /etc/ssh/sshd_config

Author: David Lutterkort lutter@redhat.com
        Dominique Dumont dominique.dumont@hp.com

About: Reference
  sshd_config man page.
  See http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5

About: License
  This file is licensed under the LGPL v2+.

About: Lens Usage
  Sample usage of this lens in augtool:

    * Get your current setup
      > print /files/etc/ssh/sshd_config
      ...

    * Set X11Forwarding to "no"
      > set /files/etc/ssh/sshd_config/X11Forwarding "no"

  More advanced usage:

    * Set a Match section
      > set /files/etc/ssh/sshd_config/Match[1]/Condition/User "foo"
      > set /files/etc/ssh/sshd_config/Match[1]/Settings/X11Forwarding "yes"

  Saving your file:

      > save

About: CAVEATS

  In sshd_config, Match blocks must be located at the end of the file.
  This means that any new "global" parameters (i.e. outside of a Match
  block) must be written before the first Match block. By default,
  Augeas will write new parameters at the end of the file.

  I.e. if you have a Match section and no ChrootDirectory parameter,
  this command:

     > set /files/etc/ssh/sshd_config/ChrootDirectory "foo"

  will be stored in a new node after the Match section and Augeas will
  refuse to save sshd_config file.

  To create a new parameter as the right place, you must first create
  a new Augeas node before the Match section:

     > ins ChrootDirectory before /files/etc/ssh/sshd_config/Match

  Then, you can set the parameter

     > set /files/etc/ssh/sshd_config/ChrootDirectory "foo"

About: Configuration files
  This lens applies to /etc/ssh/sshd_config

*)

module Sshd =
   autoload xfm

   let eol = del /[ \t]*\n/ "\n"

   let sep = del /[ \t=]+/ " "

   let indent = del /[ \t]*/ "  "

   let key_re = /[A-Za-z0-9]+/
         - /MACs|Match|AcceptEnv|Subsystem|Ciphers|(Kex|HostKey)Algorithms|(Allow|Deny)(Groups|Users)/i

   let comment = Util.comment
   let comment_noindent = Util.comment_noindent
   let empty = Util.empty

   let array_entry (kw:regexp) (sq:string) =
     let bare = Quote.do_quote_opt_nil (store /[^"' \t\n=]+/) in
     let quoted = Quote.do_quote (store /[^"'\n]*[ \t]+[^"'\n]*/) in
     [ key kw
       . ( [ sep . seq sq . bare ] | [ sep . seq sq . quoted ] )*
       . eol ]

   let other_entry =
     let value = store /[^ \t\n=]+([ \t=]+[^ \t\n=]+)*/ in
     [ key key_re . sep . value . eol ]

   let accept_env = array_entry /AcceptEnv/i "AcceptEnv"

   let allow_groups = array_entry /AllowGroups/i "AllowGroups"
   let allow_users = array_entry /AllowUsers/i "AllowUsers"
   let deny_groups = array_entry /DenyGroups/i "DenyGroups"
   let deny_users = array_entry /DenyUsers/i "DenyUsers"

   let subsystemvalue =
     let value = store (/[^ \t\n=](.*[^ \t\n=])?/) in
     [ key /[A-Za-z0-9\-]+/ . sep . value . eol ]

   let subsystem =
     [ key /Subsystem/i .  sep .  subsystemvalue ]

   let list (kw:regexp) (sq:string) =
     let value = store /[^, \t\n=]+/ in
     [ key kw . sep .
         [ seq sq . value ] .
         ([ seq sq . Util.del_str "," . value])* .
         eol ]

   let macs = list /MACs/i "MACs"

   let ciphers = list /Ciphers/i "Ciphers"

   let kexalgorithms = list /KexAlgorithms/i "KexAlgorithms"

   let hostkeyalgorithms = list /HostKeyAlgorithms/i "HostKeyAlgorithms"

   let entry = accept_env | allow_groups | allow_users
             | deny_groups | subsystem | deny_users
             | macs | ciphers | kexalgorithms | hostkeyalgorithms
             | other_entry

   let condition_entry =
    let value = store  /[^ \t\n=]+/ in
    [ sep . key /[A-Za-z0-9]+/ . sep . value ]

   let match_cond =
     [ label "Condition" . condition_entry+ . eol ]

   let match_entry = indent . (entry | comment_noindent)
                   | empty

   let match =
     [ key /Match/i . match_cond
        . [ label "Settings" .  match_entry+ ]
     ]

  let lns = (entry | comment | empty)* . match*

  let xfm = transform lns (incl "/etc/ssh/sshd_config")

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)

(*
Module: Sshd
  Parses /etc/ssh/sshd_config

Author: David Lutterkort lutter@redhat.com
        Dominique Dumont dominique.dumont@hp.com

About: Reference
  sshd_config man page.
  See http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5

About: License
  This file is licensed under the LGPL v2+.

About: Lens Usage
  Sample usage of this lens in augtool:

    * Get your current setup
      > print /files/etc/ssh/sshd_config
      ...

    * Set X11Forwarding to "no"
      > set /files/etc/ssh/sshd_config/X11Forwarding "no"

  More advanced usage:

    * Set a Match section
      > set /files/etc/ssh/sshd_config/Match[1]/Condition/User "foo"
      > set /files/etc/ssh/sshd_config/Match[1]/Settings/X11Forwarding "yes"

  Saving your file:

      > save

About: CAVEATS

  In sshd_config, Match blocks must be located at the end of the file.
  This means that any new "global" parameters (i.e. outside of a Match
  block) must be written before the first Match block. By default,
  Augeas will write new parameters at the end of the file.

  I.e. if you have a Match section and no ChrootDirectory parameter,
  this command:

     > set /files/etc/ssh/sshd_config/ChrootDirectory "foo"

  will be stored in a new node after the Match section and Augeas will
  refuse to save sshd_config file.

  To create a new parameter as the right place, you must first create
  a new Augeas node before the Match section:

     > ins ChrootDirectory before /files/etc/ssh/sshd_config/Match

  Then, you can set the parameter

     > set /files/etc/ssh/sshd_config/ChrootDirectory "foo"

About: Configuration files
  This lens applies to /etc/ssh/sshd_config

*)

module Sshd =
   autoload xfm

   let eol = del /[ \t]*\n/ "\n"

   let sep = Util.del_ws_spc

   let indent = del /[ \t]*/ "  "

   let key_re = /[A-Za-z0-9]+/
         - /MACs|Match|AcceptEnv|Subsystem|Ciphers|(Kex|HostKey)Algorithms|(Allow|Deny)(Groups|Users)/i

   let comment = Util.comment
   let comment_noindent = Util.comment_noindent
   let empty = Util.empty

   let array_entry (kw:regexp) (sq:string) =
     let bare = Quote.do_quote_opt_nil (store /[^"' \t\n]+/) in
     let quoted = Quote.do_quote (store /[^"'\n]*[ \t]+[^"'\n]*/) in
     [ key kw
       . ( [ sep . seq sq . bare ] | [ sep . seq sq . quoted ] )*
       . eol ]

   let other_entry =
     let value = store /[^ \t\n]+([ \t]+[^ \t\n]+)*/ in
     [ key key_re . sep . value . eol ]

   let accept_env = array_entry /AcceptEnv/i "AcceptEnv"

   let allow_groups = array_entry /AllowGroups/i "AllowGroups"
   let allow_users = array_entry /AllowUsers/i "AllowUsers"
   let deny_groups = array_entry /DenyGroups/i "DenyGroups"
   let deny_users = array_entry /DenyUsers/i "DenyUsers"

   let subsystemvalue =
     let value = store (/[^ \t\n](.*[^ \t\n])?/) in
     [ key /[A-Za-z0-9\-]+/ . sep . value . eol ]

   let subsystem =
     [ key /Subsystem/i .  sep .  subsystemvalue ]

   let list (kw:regexp) (sq:string) =
     let value = store /[^, \t\n]+/ in
     [ key kw . sep .
         [ seq sq . value ] .
         ([ seq sq . Util.del_str "," . value])* .
         eol ]

   let macs = list /MACs/i "MACs"

   let ciphers = list /Ciphers/i "Ciphers"

   let kexalgorithms = list /KexAlgorithms/i "KexAlgorithms"

   let hostkeyalgorithms = list /HostKeyAlgorithms/i "HostKeyAlgorithms"

   let entry = accept_env | allow_groups | allow_users
             | deny_groups | subsystem | deny_users
             | macs | ciphers | kexalgorithms | hostkeyalgorithms
             | other_entry

   let condition_entry =
    let value = store  /[^ \t\n]+/ in
    [ sep . key /[A-Za-z0-9]+/ . sep . value ]

   let match_cond =
     [ label "Condition" . condition_entry+ . eol ]

   let match_entry = indent . (entry | comment_noindent)
                   | empty

   let match =
     [ key /Match/i . match_cond
        . [ label "Settings" .  match_entry+ ]
     ]

  let lns = (entry | comment | empty)* . match*

  let xfm = transform lns (incl "/etc/ssh/sshd_config")

(* Local Variables: *)
(* mode: caml       *)
(* End:             *)