Update the resolv lens (#708)

Update the resolv lens (#708)

Closes: #707

(*
Module: Resolv
  Parses /etc/resolv.conf

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
  This lens tries to keep as close as possible to `man resolv.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/resolv.conf. See <filter>.
*)

module Resolv =
autoload xfm

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

(* View: comment *)
let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# "

(* View: comment_eol *)
let comment_eol = Util.comment_generic /[ \t]*[;#][ \t]*/ " # "

(* View: empty *)
let empty = Util.empty_generic_dos /[ \t]*[#;]?[ \t]*/

(************************************************************************
 * Group:                 MAIN OPTIONS
 *************************************************************************)

(* View: netmask
A network mask for IP addresses *)
let netmask = [ label "netmask" . Util.del_str "/" . store Rx.ip ]

(* View: ipaddr
An IP address or range with an optional mask *)
let ipaddr = [label "ipaddr" . store Rx.ip . netmask?]

(* View: nameserver
     A nameserver entry *)
let nameserver = Build.key_value_line_comment
                    "nameserver" Sep.space (store Rx.ip) comment_eol

(* View: domain *)
let domain = Build.key_value_line_comment
                    "domain" Sep.space (store Rx.word) comment_eol

(* View: search *)
let search = Build.key_value_line_comment
                    "search" Sep.space
                    (Build.opt_list
                           [label "domain" . store Rx.word]
                            Sep.space)
                    comment_eol

(* View: sortlist *)
let sortlist = Build.key_value_line_comment
                    "sortlist" Sep.space
                    (Build.opt_list
                           ipaddr
                           Sep.space)
                    comment_eol

(* View: lookup *)
let lookup =
  let lookup_entry = Build.flag("bind"|"file"|"yp")
    in Build.key_value_line_comment
             "lookup" Sep.space
             (Build.opt_list
                    lookup_entry
                    Sep.space)
             comment_eol

(* View: family *)
let family =
  let family_entry = Build.flag("inet4"|"inet6")
    in Build.key_value_line_comment
             "family" Sep.space
             (Build.opt_list
                    family_entry
                    Sep.space)
             comment_eol

(************************************************************************
 * Group:                 SPECIAL OPTIONS
 *************************************************************************)

(* View: ip6_dotint
     ip6-dotint option, which supports negation *)
let ip6_dotint =
  let negate = [ del "no-" "no-" . label "negate" ]
    in [ negate? . key "ip6-dotint" ]

(* View: options
     Options values *)
let options =
      let options_entry = Build.key_value ("ndots"|"timeout"|"attempts")
                                          (Util.del_str ":") (store Rx.integer)
                        | Build.flag ("debug"|"rotate"|"no-check-names"
                                     |"inet6"|"ip6-bytestring"|"edns0"
                                     |"single-request"|"single-request-reopen"
                                     |"no-tld-query"|"use-vc"|"no-reload")
                        | ip6_dotint

            in Build.key_value_line_comment
                    "options" Sep.space
                    (Build.opt_list
                           options_entry
                           Sep.space)
                    comment_eol

(* View: entry *)
let entry = nameserver
          | domain
          | search
          | sortlist
          | options
          | lookup
          | family

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

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

let xfm = transform lns filter

(*
Module: Resolv
  Parses /etc/resolv.conf

Author: Raphael Pinson <raphink@gmail.com>

About: Reference
  This lens tries to keep as close as possible to `man resolv.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/resolv.conf. See <filter>.
*)

module Resolv =
autoload xfm

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

(* View: comment *)
let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# "

(* View: comment_eol *)
let comment_eol = Util.comment_generic /[ \t]*[;#][ \t]*/ " # "

(* View: empty *)
let empty = Util.empty_generic_dos /[ \t]*[#;]?[ \t]*/

(************************************************************************
 * Group:                 MAIN OPTIONS
 *************************************************************************)

(* View: netmask
A network mask for IP addresses *)
let netmask = [ label "netmask" . Util.del_str "/" . store Rx.ip ]

(* View: ipaddr
An IP address or range with an optional mask *)
let ipaddr = [label "ipaddr" . store Rx.ip . netmask?]

(* View: nameserver
     A nameserver entry *)
let nameserver = Build.key_value_line_comment
                    "nameserver" Sep.space (store Rx.ip) comment_eol

(* View: domain *)
let domain = Build.key_value_line_comment
                    "domain" Sep.space (store Rx.word) comment_eol

(* View: search *)
let search = Build.key_value_line_comment
                    "search" Sep.space
                    (Build.opt_list
                           [label "domain" . store Rx.word]
                            Sep.space)
                    comment_eol

(* View: sortlist *)
let sortlist = Build.key_value_line_comment
                    "sortlist" Sep.space
                    (Build.opt_list
                           ipaddr
                           Sep.space)
                    comment_eol

(* View: lookup *)
let lookup =
  let lookup_entry = Build.flag("bind"|"file"|"yp")
    in Build.key_value_line_comment
             "lookup" Sep.space
             (Build.opt_list
                    lookup_entry
                    Sep.space)
             comment_eol

(* View: family *)
let family =
  let family_entry = Build.flag("inet4"|"inet6")
    in Build.key_value_line_comment
             "family" Sep.space
             (Build.opt_list
                    family_entry
                    Sep.space)
             comment_eol

(************************************************************************
 * Group:                 SPECIAL OPTIONS
 *************************************************************************)

(* View: ip6_dotint
     ip6-dotint option, which supports negation *)
let ip6_dotint =
  let negate = [ del "no-" "no-" . label "negate" ]
    in [ negate? . key "ip6-dotint" ]

(* View: options
     Options values *)
let options =
      let options_entry = Build.key_value ("ndots"|"timeout"|"attempts")
                                          (Util.del_str ":") (store Rx.integer)
                        | Build.flag ("debug"|"rotate"|"no-check-names"
                                     |"inet6"|"ip6-bytestring"|"edns0"
				     |"single-request-reopen")
                        | ip6_dotint

            in Build.key_value_line_comment
                    "options" Sep.space
                    (Build.opt_list
                           options_entry
                           Sep.space)
                    comment_eol

(* View: entry *)
let entry = nameserver
          | domain
          | search
          | sortlist
          | options
          | lookup
          | family

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

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

let xfm = transform lns filter


Hooks without any lines are valid in logrotate.aug

(* Logrotate module for Augeas                *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(* Patches from:                              *)
(*   Sean Millichamp <sean@bruenor.org>       *)
(*                                            *)
(* Supported :                                *)
(*   - defaults                               *)
(*   - rules                                  *)
(*   - (pre|post)rotate entries               *)
(*                                            *)
(* Todo :                                     *)
(*                                            *)

module Logrotate =
   autoload xfm

   let sep_spc = Util.del_ws_spc
   let sep_val = del /[ \t]*=[ \t]*|[ \t]+/ " "
   let eol = Util.eol
   let num = /[0-9]+/
   let word = /[^,#= \n\t{}]+/
   let filename = /\/[^,#= \n\t{}]+/
   let size = num . /[kMG]?/

   (* define comments and empty lines *)
   let comment (indent:string) =
     let nl = Util.del_str "\n" in
     [ label "#comment" . del /[ \t]*/ indent . del /#[ \t]*/ "# " .  store /([^ \t\n].*)?/ . nl ]
   let empty   = [ del /[ \t]*\n/ "\n" ]

   (* Useful functions *)

   let list_item = [ sep_spc . key /[^\/+,# \n\t{}]+/ ]
   let select_to_eol (kw:string) (select:regexp) (indent:string) = [ del /[ \t]*/ indent . label kw . store select . eol ]
   let value_to_eol (kw:string) (value:regexp) (indent:string )  = [ del /[ \t]*/ indent . key kw . sep_val . store value . eol ]
   let flag_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . eol ]
   let list_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . list_item+ . eol ]

   (* Defaults *)

   let create (indent:string ) =
     let mode = sep_spc . [ label "mode" . store num ] in
     let owner = sep_spc . [ label "owner" . store word ] in
     let group = sep_spc . [ label "group" . store word ] in
     [ del /[ \t]*/ indent . key "create" .
         ( mode | mode . owner | mode . owner . group )?
		    . eol ]

   let tabooext (indent:string) = [ del /[ \t]*/ indent . key "tabooext" . ( sep_spc . store /\+/ )? . list_item+ . eol ]

   let attrs (indent:string) = select_to_eol "schedule" /(daily|weekly|monthly|yearly)/ indent
                | value_to_eol "rotate" num indent
		| create indent
		| flag_to_eol "nocreate" indent
		| value_to_eol "include" word indent
		| select_to_eol "missingok" /(no)?missingok/ indent
		| select_to_eol "compress" /(no)?compress/ indent
		| select_to_eol "delaycompress" /(no)?delaycompress/ indent
		| select_to_eol "ifempty" /(not)?ifempty/ indent
		| select_to_eol "sharedscripts" /(no)?sharedscripts/ indent
		| value_to_eol "size" size indent
		| tabooext indent
		| value_to_eol "olddir" word indent
		| flag_to_eol "noolddir" indent
		| value_to_eol "mail" word indent
		| flag_to_eol "mailfirst" indent
		| flag_to_eol "maillast" indent
		| flag_to_eol "nomail" indent
		| value_to_eol "errors" word indent
		| value_to_eol "extension" word indent
		| select_to_eol "dateext" /(no)?dateext/ indent
		| value_to_eol "compresscmd" word indent
		| value_to_eol "uncompresscmd" word indent
		| value_to_eol "compressext" word indent
		| list_to_eol "compressoptions" indent
		| select_to_eol "copy" /(no)?copy/ indent
		| select_to_eol "copytruncate" /(no)?copytruncate/ indent
		| value_to_eol "maxage" num indent
		| value_to_eol "minsize" size indent
		| select_to_eol "shred" /(no)?shred/ indent
		| value_to_eol "shredcycles" num indent
		| value_to_eol "start" num indent

   (* Define hooks *)

   let hook_lines =
     let line_re = /.*/ - /[ \t]*endscript[ \t]*/ in
       store ( line_re . ("\n" . line_re)* )? . del "\n" "\n"

   let hooks =
     let hook_names = /(pre|post)rotate|(first|last)action/ in
     [ del /[ \t]*/ "\t" . key hook_names . eol .
       hook_lines? .
       del /[ \t]*endscript[ \t]*\n/ "\tendscript\n" ]

   (* Define rule *)

   let body = del /\{[ \t]*\n/ "{\n"
                       . ( comment "\t" | attrs "\t" | hooks | empty )*
                       . del /[ \t]*\}[ \t]*\n/ "}\n"

   let rule =
     [ label "rule" . Util.indent .
         [ label "file" . store filename ] .
	 [ del /[ \t\n]+/ " " . label "file" . store filename ]* .
	 del /[ \t\n]*/ " " . body ]

   let lns = ( comment "" | empty | attrs "" | rule )*

   let filter = incl "/etc/logrotate.d/*"
              . incl "/etc/logrotate.conf"
	      . Util.stdexcl

   let xfm = transform lns filter

(* Logrotate module for Augeas                *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(* Patches from:                              *)
(*   Sean Millichamp <sean@bruenor.org>       *)
(*                                            *)
(* Supported :                                *)
(*   - defaults                               *)
(*   - rules                                  *)
(*   - (pre|post)rotate entries               *)
(*                                            *)
(* Todo :                                     *)
(*                                            *)

module Logrotate =
   autoload xfm

   let sep_spc = Util.del_ws_spc
   let sep_val = del /[ \t]*=[ \t]*|[ \t]+/ " "
   let eol = Util.eol
   let num = /[0-9]+/
   let word = /[^,#= \n\t{}]+/
   let filename = /\/[^,#= \n\t{}]+/
   let size = num . /[kMG]?/

   (* define comments and empty lines *)
   let comment (indent:string) =
     let nl = Util.del_str "\n" in
     [ label "#comment" . del /[ \t]*/ indent . del /#[ \t]*/ "# " .  store /([^ \t\n].*)?/ . nl ]
   let empty   = [ del /[ \t]*\n/ "\n" ]

   (* Useful functions *)

   let list_item = [ sep_spc . key /[^\/+,# \n\t{}]+/ ]
   let select_to_eol (kw:string) (select:regexp) (indent:string) = [ del /[ \t]*/ indent . label kw . store select . eol ]
   let value_to_eol (kw:string) (value:regexp) (indent:string )  = [ del /[ \t]*/ indent . key kw . sep_val . store value . eol ]
   let flag_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . eol ]
   let list_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . list_item+ . eol ]

   (* Defaults *)

   let create (indent:string ) =
     let mode = sep_spc . [ label "mode" . store num ] in
     let owner = sep_spc . [ label "owner" . store word ] in
     let group = sep_spc . [ label "group" . store word ] in
     [ del /[ \t]*/ indent . key "create" .
         ( mode | mode . owner | mode . owner . group )?
		    . eol ]

   let tabooext (indent:string) = [ del /[ \t]*/ indent . key "tabooext" . ( sep_spc . store /\+/ )? . list_item+ . eol ]

   let attrs (indent:string) = select_to_eol "schedule" /(daily|weekly|monthly|yearly)/ indent
                | value_to_eol "rotate" num indent
		| create indent
		| flag_to_eol "nocreate" indent
		| value_to_eol "include" word indent
		| select_to_eol "missingok" /(no)?missingok/ indent
		| select_to_eol "compress" /(no)?compress/ indent
		| select_to_eol "delaycompress" /(no)?delaycompress/ indent
		| select_to_eol "ifempty" /(not)?ifempty/ indent
		| select_to_eol "sharedscripts" /(no)?sharedscripts/ indent
		| value_to_eol "size" size indent
		| tabooext indent
		| value_to_eol "olddir" word indent
		| flag_to_eol "noolddir" indent
		| value_to_eol "mail" word indent
		| flag_to_eol "mailfirst" indent
		| flag_to_eol "maillast" indent
		| flag_to_eol "nomail" indent
		| value_to_eol "errors" word indent
		| value_to_eol "extension" word indent
		| select_to_eol "dateext" /(no)?dateext/ indent
		| value_to_eol "compresscmd" word indent
		| value_to_eol "uncompresscmd" word indent
		| value_to_eol "compressext" word indent
		| list_to_eol "compressoptions" indent
		| select_to_eol "copy" /(no)?copy/ indent
		| select_to_eol "copytruncate" /(no)?copytruncate/ indent
		| value_to_eol "maxage" num indent
		| value_to_eol "minsize" size indent
		| select_to_eol "shred" /(no)?shred/ indent
		| value_to_eol "shredcycles" num indent
		| value_to_eol "start" num indent

   (* Define hooks *)

   let hook_lines =
     let line_re = /.*/ - /[ \t]*endscript[ \t]*/ in
       store ( line_re . ("\n" . line_re)* )? . del "\n" "\n"

   let hooks =
     let hook_names = /(pre|post)rotate|(first|last)action/ in
     [ del /[ \t]*/ "\t" . key hook_names . eol .
       hook_lines .
       del /[ \t]*endscript[ \t]*\n/ "\tendscript\n" ]

   (* Define rule *)

   let body = del /\{[ \t]*\n/ "{\n"
                       . ( comment "\t" | attrs "\t" | hooks | empty )*
                       . del /[ \t]*\}[ \t]*\n/ "}\n"

   let rule =
     [ label "rule" . Util.indent .
         [ label "file" . store filename ] .
	 [ del /[ \t\n]+/ " " . label "file" . store filename ]* .
	 del /[ \t\n]*/ " " . body ]

   let lns = ( comment "" | empty | attrs "" | rule )*

   let filter = incl "/etc/logrotate.d/*"
              . incl "/etc/logrotate.conf"
	      . Util.stdexcl

   let xfm = transform lns filter


Shellvars: process /etc/environment

Shellvars: process /etc/environment

(* Generic lens for shell-script config files like the ones found *)
(* in /etc/sysconfig                                              *)
module Shellvars =
  autoload xfm

  let eol = Util.eol

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let eq = Util.del_str "="
  let comment = Util.comment
  let empty   = Util.empty
  let xchgs   = Build.xchgs

  let char  = /[^() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  let bquot = /`[^`\n]*`/

  (* 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 (char+ | dquot) 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 (char* | dquot | squot | bquot | empty_array)

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

  let var_action (name:string) =
    [ xchgs name ("@" . name) . Util.del_ws_spc . store key_re . eol ]

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

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

  let lns = (comment | empty | source | kv | unset | bare_export) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let filter_sysconfig =
      sc_incl "atd" .
      sc_incl "authconfig" .
      sc_incl "autofs" .
      sc_incl "clock" .
      sc_incl "cpuspeed" .
      sc_incl "crond" .
      sc_incl "crontab" .
      sc_incl "desktop" .
      sc_incl "firstboot" .
      sc_incl "grub" .
      sc_incl "hsqldb" .
      sc_incl "httpd" .
      sc_incl "i18n" .
      sc_incl "init" .
      sc_incl "iptables-config" .
      sc_incl "irda" .
      sc_incl "irqbalance" .
      sc_incl "kdump" .
      sc_incl "kernel" .
      sc_incl "keyboard" .
      sc_incl "kudzu" .
      sc_incl "libvirtd" .
      sc_incl "lircd" .
      sc_incl "nasd" .
      sc_incl "netconsole" .
      sc_incl "network" .
      sc_incl "nfs" .
      sc_incl "ntpd" .
      sc_incl "prelink" .
      sc_incl "readonly-root" .
      sc_incl "rsyslog" .
      sc_incl "samba" .
      sc_incl "saslauthd" .
      sc_incl "selinux" .
      sc_incl "sendmail" .
      sc_incl "smartmontools" .
      sc_incl "spamassassin" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_ifcfg   = incl "/etc/sysconfig/network-scripts/ifcfg-*"
                     . incl "/etc/sysconfig/network/ifcfg-*"
  let filter_default = incl "/etc/default/*"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"

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

  let xfm = transform lns filter

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

(* Generic lens for shell-script config files like the ones found *)
(* in /etc/sysconfig                                              *)
module Shellvars =
  autoload xfm

  let eol = Util.eol

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let eq = Util.del_str "="
  let comment = Util.comment
  let empty   = Util.empty
  let xchgs   = Build.xchgs

  let char  = /[^() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  let bquot = /`[^`\n]*`/

  (* 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 (char+ | dquot) 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 (char* | dquot | squot | bquot | empty_array)

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

  let var_action (name:string) =
    [ xchgs name ("@" . name) . Util.del_ws_spc . store key_re . eol ]

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

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

  let lns = (comment | empty | source | kv | unset | bare_export) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let filter_sysconfig =
      sc_incl "atd" .
      sc_incl "authconfig" .
      sc_incl "autofs" .
      sc_incl "clock" .
      sc_incl "cpuspeed" .
      sc_incl "crond" .
      sc_incl "crontab" .
      sc_incl "desktop" .
      sc_incl "firstboot" .
      sc_incl "grub" .
      sc_incl "hsqldb" .
      sc_incl "httpd" .
      sc_incl "i18n" .
      sc_incl "init" .
      sc_incl "iptables-config" .
      sc_incl "irda" .
      sc_incl "irqbalance" .
      sc_incl "kdump" .
      sc_incl "kernel" .
      sc_incl "keyboard" .
      sc_incl "kudzu" .
      sc_incl "libvirtd" .
      sc_incl "lircd" .
      sc_incl "nasd" .
      sc_incl "netconsole" .
      sc_incl "network" .
      sc_incl "nfs" .
      sc_incl "ntpd" .
      sc_incl "prelink" .
      sc_incl "readonly-root" .
      sc_incl "rsyslog" .
      sc_incl "samba" .
      sc_incl "saslauthd" .
      sc_incl "selinux" .
      sc_incl "sendmail" .
      sc_incl "smartmontools" .
      sc_incl "spamassassin" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_ifcfg   = incl "/etc/sysconfig/network-scripts/ifcfg-*"
                     . incl "/etc/sysconfig/network/ifcfg-*"
  let filter_default = incl "/etc/default/*"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
  let filter = filter_sysconfig
             . filter_ifcfg
             . filter_default
             . filter_misc
             . Util.stdexcl

  let xfm = transform lns filter

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


Slapd: remove duplicate entry in database_re

(* Slapd module for Augeas
   Author: Free Ekanayaka <free@64studio.com>

   Reference: man slapd.conf(5), man slapd.access (5)

*)

module Slapd =
  autoload xfm

(************************************************************************
 *                           USEFUL PRIMITIVES
 *************************************************************************)

let eol         = Util.eol
let spc         = Util.del_ws_spc
let sep         = del /[ \t\n]+/ " "

let sto_to_eol  = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
let sto_to_spc  = store /[^\\# \t\n]+/
let sto_to_by   = store (/[^\\# \t\n]+/ - "by")

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

(************************************************************************
 *                           ACCESS TO
 *************************************************************************)

let access_re   = "access to"
let who         = [ spc . label "who"     . sto_to_spc ]
let what        = [ spc . label "access"  . sto_to_by ]

(* TODO: parse the control field, see man slapd.access (5) *)
let control     = [ spc . label "control" . sto_to_by  ]
let by          = [ sep . key "by". who . (what . control?)? ]

let access      = [ key access_re . spc. sto_to_spc . by+ . eol ]

(************************************************************************
 *                             GLOBAL
 *************************************************************************)

(* TODO: parse special field separately, see man slapd.conf (5) *)
let global_re   = "allow"
                | "argsfile"
                | "attributeoptions"
                | "attributetype"
                | "authz-policy"
                | "ldap"
                | "dn"
                | "concurrency"
                | "cron_max_pending"
                | "conn_max_pending_auth"
                | "defaultsearchbase"
                | "disallow"
                | "ditcontentrule"
                | "gentlehup"
                | "idletimeout"
                | "include"
                | "index_substr_if_minlen"
                | "index_substr_if_maxlen"
                | "index_substr_any_len"
                | "index_substr_any_step"
                | "localSSF"
                | "loglevel"
                | "moduleload"
                | "modulepath"
                | "objectclass"
                | "objectidentifier"
                | "password-hash"
                | "password-crypt-salt-format"
                | "pidfile"
                | "referral"
                | "replica-argsfile"
                | "replica-pidfile"
                | "replicationinterval"
                | "require"
                | "reverse-lookup"
                | "rootDSE"
                | "sasl-host "
                | "sasl-realm"
                | "sasl-secprops"
                | "schemadn"
                | "security"
                | "sizelimit"
                | "sockbuf_max_incoming "
                | "sockbuf_max_incoming_auth"
                | "threads"
                | "timelimit time"
                | "tool-threads"
                | "TLSCipherSuite"
                | "TLSCACertificateFile"
                | "TLSCACertificatePath"
                | "TLSCertificateFile"
                | "TLSCertificateKeyFile"
                | "TLSDHParamFile"
                | "TLSRandFile"
                | "TLSVerifyClient"
                | "TLSCRLCheck"
                | "backend"

let global     = Build.key_ws_value global_re

(************************************************************************
 *                             DATABASE
 *************************************************************************)

(* TODO: support all types of database backend *)
let database_hdb = "cachesize"
                | "cachefree"
                | "checkpoint"
                | "dbconfig"
                | "dbnosync"
                | "directory"
                | "dirtyread"
                | "idlcachesize"
                | "index"
                | "linearindex"
                | "lockdetect"
                | "mode"
                | "searchstack"
                | "shm_key"

let database_re = "suffix"
                | "lastmod"
                | "limits"
                | "maxderefdepth"
                | "overlay"
                | "readonly"
                | "replica uri"
                | "replogfile"
                | "restrict"
                | "rootdn"
                | "rootpw"
                | "subordinate"
                | "syncrepl rid"
                | "updatedn"
                | "updateref"
                | database_hdb

let database    = [ key "database"
                  . spc
                  . sto_to_eol
                  . eol
                  . (comment|empty|Build.key_ws_value database_re|access)* ]

(************************************************************************
 *                              LENS
 *************************************************************************)

let lns         = (comment|empty|global|access)* . (database)*

let filter      = incl "/etc/ldap/slapd.conf"
                . incl "/etc/openldap/slapd.conf"

let xfm         = transform lns filter

(* Slapd module for Augeas
   Author: Free Ekanayaka <free@64studio.com>

   Reference: man slapd.conf(5), man slapd.access (5)

*)

module Slapd =
  autoload xfm

(************************************************************************
 *                           USEFUL PRIMITIVES
 *************************************************************************)

let eol         = Util.eol
let spc         = Util.del_ws_spc
let sep         = del /[ \t\n]+/ " "

let sto_to_eol  = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/
let sto_to_spc  = store /[^\\# \t\n]+/
let sto_to_by   = store (/[^\\# \t\n]+/ - "by")

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

(************************************************************************
 *                           ACCESS TO
 *************************************************************************)

let access_re   = "access to"
let who         = [ spc . label "who"     . sto_to_spc ]
let what        = [ spc . label "access"  . sto_to_by ]

(* TODO: parse the control field, see man slapd.access (5) *)
let control     = [ spc . label "control" . sto_to_by  ]
let by          = [ sep . key "by". who . (what . control?)? ]

let access      = [ key access_re . spc. sto_to_spc . by+ . eol ]

(************************************************************************
 *                             GLOBAL
 *************************************************************************)

(* TODO: parse special field separately, see man slapd.conf (5) *)
let global_re   = "allow"
                | "argsfile"
                | "attributeoptions"
                | "attributetype"
                | "authz-policy"
                | "ldap"
                | "dn"
                | "concurrency"
                | "cron_max_pending"
                | "conn_max_pending_auth"
                | "defaultsearchbase"
                | "disallow"
                | "ditcontentrule"
                | "gentlehup"
                | "idletimeout"
                | "include"
                | "index_substr_if_minlen"
                | "index_substr_if_maxlen"
                | "index_substr_any_len"
                | "index_substr_any_step"
                | "localSSF"
                | "loglevel"
                | "moduleload"
                | "modulepath"
                | "objectclass"
                | "objectidentifier"
                | "password-hash"
                | "password-crypt-salt-format"
                | "pidfile"
                | "referral"
                | "replica-argsfile"
                | "replica-pidfile"
                | "replicationinterval"
                | "require"
                | "reverse-lookup"
                | "rootDSE"
                | "sasl-host "
                | "sasl-realm"
                | "sasl-secprops"
                | "schemadn"
                | "security"
                | "sizelimit"
                | "sockbuf_max_incoming "
                | "sockbuf_max_incoming_auth"
                | "threads"
                | "timelimit time"
                | "tool-threads"
                | "TLSCipherSuite"
                | "TLSCACertificateFile"
                | "TLSCACertificatePath"
                | "TLSCertificateFile"
                | "TLSCertificateKeyFile"
                | "TLSDHParamFile"
                | "TLSRandFile"
                | "TLSVerifyClient"
                | "TLSCRLCheck"
                | "backend"

let global     = Build.key_ws_value global_re

(************************************************************************
 *                             DATABASE
 *************************************************************************)

(* TODO: support all types of database backend *)
let database_hdb = "cachesize"
                | "cachefree"
                | "checkpoint"
                | "dbconfig"
                | "dbnosync"
                | "directory"
                | "dirtyread"
                | "idlcachesize"
                | "index"
                | "linearindex"
                | "lockdetect"
                | "mode"
                | "searchstack"
                | "shm_key"

let database_re = "suffix"
                | "lastmod"
                | "limits"
                | "maxderefdepth"
                | "overlay"
                | "readonly"
                | "replica uri"
                | "replogfile"
                | "restrict"
                | "rootdn"
                | "rootpw"
                | "suffix"
                | "subordinate"
                | "syncrepl rid"
                | "updatedn"
                | "updateref"
                | database_hdb

let database    = [ key "database"
                  . spc
                  . sto_to_eol
                  . eol
                  . (comment|empty|Build.key_ws_value database_re|access)* ]

(************************************************************************
 *                              LENS
 *************************************************************************)

let lns         = (comment|empty|global|access)* . (database)*

let filter      = incl "/etc/ldap/slapd.conf"
                . incl "/etc/openldap/slapd.conf"

let xfm         = transform lns filter


Toml: time_re can start with one digit only

(*
Module: Toml
  Parses TOML files

Author: Raphael Pinson <raphael.pinson@camptocamp.com>

About: Reference
  https://github.com/mojombo/toml/blob/master/README.md

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to TOML files.

About: Examples
   The <Test_Toml> file contains various examples and tests.
*)

module Toml =

(* Group: base definitions *)

(* View: comment
     A simple comment *)
let comment  = IniFile.comment "#" "#"

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

(* View: eol
     An end of line *)
let eol = Util.eol

(* Group: value entries *)

let bare_re_noquot = (/[^][", \t\r\n]/ - "#")
let bare_re = (/[^][,\r=]/ - "#")+
let no_quot = /[^]["\r\n]*/
let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?))
let quoted = Quote.do_dquote (store (/[^"]/ . "#"* . /[^"]/))

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

let space_or_empty = [ del /[ \t\n]+/ " " ]

let comma = Util.del_str "," . (space_or_empty | comment)?
let lbrace = Util.del_str "{" . (space_or_empty | comment)?
let rbrace = Util.del_str "}"
let lbrack = Util.del_str "[" . (space_or_empty | comment)?
let rbrack = Util.del_str "]"

(* This follows the definition of 'string' at https://www.json.org/
   It's a little wider than what's allowed there as it would accept
   nonsensical \u escapes *)
let triple_dquote = Util.del_str "\"\"\""
let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote

let str_store_multi = triple_dquote . eol
                  . store /([^\\"]|\\\\["\/bfnrtu\\])*/
                  . del /\n[ \t]*/ "\n" . triple_dquote

let str_store_literal = Quote.squote . store /([^\\']|\\\\['\/bfnrtu\\])*/ . Quote.squote

let integer =
     let base10 = /[+-]?[0-9_]+/
  in let hex = /0x[A-Za-z0-9]+/
  in let oct = /0o[0-7]+/
  in let bin = /0b[01]+/
  in [ label "integer" . store (base10 | hex | oct | bin) ]

let float =
     let n = /[0-9_]+/
  in let pm = /[+-]?/
  in let z = pm . n
  in let decim = "." . n
  in let exp = /[Ee]/ . z
  in let num = z . decim | z . exp | z . decim . exp
  in let inf = pm . "inf"
  in let nan = pm . "nan"
  in [ label "float" . store (num | inf | nan) ]

let str = [ label "string" . str_store ]

let str_multi = [ label "string_multi" . str_store_multi ]

let str_literal = [ label "string_literal" . str_store_literal ]

let bool (r:regexp) = [ label "bool" . store r ]

let date_re = /[0-9]{4}-[0-9]{2}-[0-9]{2}/
let time_re = /[0-9]{1,2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?[A-Z]*/

let datetime = [ label "datetime" . store (date_re . /[T ]/ . time_re) ]
let date = [ label "date" . store date_re ]
let time = [ label "time" . store time_re ]

let norec = str | str_multi | str_literal
          | integer | float | bool /true|false/
          | datetime | date |  time

let array (value:lens) = [ label "array" . lbrack
               . ( ( Build.opt_list value comma . space_or_empty? . rbrack )
                   | rbrack ) ]

let array_norec = array norec

let rec array_rec = array (norec | array_rec)

let entry_base (value:lens) = [ label "entry" . store Rx.word . Sep.space_equal . value ]

let inline_table (value:lens) = [ label "inline_table" . lbrace
                   . ( (Build.opt_list (entry_base value) comma . space_or_empty? . rbrace)
                      | rbrace ) ]

let entry = [ label "entry" . Util.indent . store Rx.word . Sep.space_equal
            . (norec | array_rec | inline_table norec) . (eol | comment) ]

(* Group: tables *)

(* View: table_gen
     A generic table *)
let table_gen (name:string) (lbrack:string) (rbrack:string) =
     let title = Util.indent . label name
               . Util.del_str lbrack
               . store /[^]\r\n.]+(\.[^]\r\n.]+)*/
               . Util.del_str rbrack . eol
  in [ title . (entry|empty|comment)* ]

(* View: table
     A table or array of tables *)
let table = table_gen "table" "[" "]"
          | table_gen "@table" "[[" "]]"

(* Group: lens *)

(* View: lns
     The Toml lens *)
let lns = (entry | empty | comment)* . table*

(*
Module: Toml
  Parses TOML files

Author: Raphael Pinson <raphael.pinson@camptocamp.com>

About: Reference
  https://github.com/mojombo/toml/blob/master/README.md

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to TOML files.

About: Examples
   The <Test_Toml> file contains various examples and tests.
*)

module Toml =

(* Group: base definitions *)

(* View: comment
     A simple comment *)
let comment  = IniFile.comment "#" "#"

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

(* View: eol
     An end of line *)
let eol = Util.eol

(* Group: value entries *)

let bare_re_noquot = (/[^][", \t\r\n]/ - "#")
let bare_re = (/[^][,\r=]/ - "#")+
let no_quot = /[^]["\r\n]*/
let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?))
let quoted = Quote.do_dquote (store (/[^"]/ . "#"* . /[^"]/))

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

let space_or_empty = [ del /[ \t\n]+/ " " ]

let comma = Util.del_str "," . (space_or_empty | comment)?
let lbrace = Util.del_str "{" . (space_or_empty | comment)?
let rbrace = Util.del_str "}"
let lbrack = Util.del_str "[" . (space_or_empty | comment)?
let rbrack = Util.del_str "]"

(* This follows the definition of 'string' at https://www.json.org/
   It's a little wider than what's allowed there as it would accept
   nonsensical \u escapes *)
let triple_dquote = Util.del_str "\"\"\""
let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote

let str_store_multi = triple_dquote . eol
                  . store /([^\\"]|\\\\["\/bfnrtu\\])*/
                  . del /\n[ \t]*/ "\n" . triple_dquote

let str_store_literal = Quote.squote . store /([^\\']|\\\\['\/bfnrtu\\])*/ . Quote.squote

let integer =
     let base10 = /[+-]?[0-9_]+/
  in let hex = /0x[A-Za-z0-9]+/
  in let oct = /0o[0-7]+/
  in let bin = /0b[01]+/
  in [ label "integer" . store (base10 | hex | oct | bin) ]

let float =
     let n = /[0-9_]+/
  in let pm = /[+-]?/
  in let z = pm . n
  in let decim = "." . n
  in let exp = /[Ee]/ . z
  in let num = z . decim | z . exp | z . decim . exp
  in let inf = pm . "inf"
  in let nan = pm . "nan"
  in [ label "float" . store (num | inf | nan) ]

let str = [ label "string" . str_store ]

let str_multi = [ label "string_multi" . str_store_multi ]

let str_literal = [ label "string_literal" . str_store_literal ]

let bool (r:regexp) = [ label "bool" . store r ]

let date_re = /[0-9]{4}-[0-9]{2}-[0-9]{2}/
let time_re = /[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?[A-Z]*/

let datetime = [ label "datetime" . store (date_re . /[T ]/ . time_re) ]
let date = [ label "date" . store date_re ]
let time = [ label "time" . store time_re ]

let norec = str | str_multi | str_literal
          | integer | float | bool /true|false/
          | datetime | date |  time

let array (value:lens) = [ label "array" . lbrack
               . ( ( Build.opt_list value comma . space_or_empty? . rbrack )
                   | rbrack ) ]

let array_norec = array norec

let rec array_rec = array (norec | array_rec)

let entry_base (value:lens) = [ label "entry" . store Rx.word . Sep.space_equal . value ]

let inline_table (value:lens) = [ label "inline_table" . lbrace
                   . ( (Build.opt_list (entry_base value) comma . space_or_empty? . rbrace)
                      | rbrace ) ]

let entry = [ label "entry" . Util.indent . store Rx.word . Sep.space_equal
            . (norec | array_rec | inline_table norec) . (eol | comment) ]

(* Group: tables *)

(* View: table_gen
     A generic table *)
let table_gen (name:string) (lbrack:string) (rbrack:string) =
     let title = Util.indent . label name
               . Util.del_str lbrack
               . store /[^]\r\n.]+(\.[^]\r\n.]+)*/
               . Util.del_str rbrack . eol
  in [ title . (entry|empty|comment)* ]

(* View: table
     A table or array of tables *)
let table = table_gen "table" "[" "]"
          | table_gen "@table" "[[" "]]"

(* Group: lens *)

(* View: lns
     The Toml lens *)
let lns = (entry | empty | comment)* . table*


not necessary anymore.

not necessary anymore.

module Trafficserver_ssl_multicert =
  autoload ssl_multicert_xfm

  let indent = Util.indent
  let spc = Sep.space
  let eol = Util.comment_or_eol

  let storage_filter = incl "/etc/trafficserver/ssl_multicert.config"

  let entry =
    let var = Build.key_value Rx.word  Sep.equal (store Rx.no_spaces)
    in [ indent . seq "entry" . Build.opt_list var Sep.space . Util.eol ]

  let ssl_multicert_lns = (Util.empty | Util.comment | entry)*

  let ssl_multicert_xfm = transform ssl_multicert_lns storage_filter


Added node config for OpenShift

Added node config for OpenShift

When the intial lens was developed there was a missing transform
on /etc/openshift/node.conf

This is a fix for bug hercules-team/augeas#22

(*
Module: OpenShift_Config
  Parses
    - /etc/openshift/broker.conf
    - /etc/openshift/broker-dev.conf
    - /etc/openshift/console.conf
    - /etc/openshift/console-dev.conf
    - /etc/openshift/node.conf
    - /etc/openshift/plugins.d/*.conf

Author: Brian Redbeard <redbeard@dead-city.org>

About: License
   This file is licenced under the LGPL v2+, conforming to the other components
   of Augeas.

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

    * Get your current setup
      > print /files/etc/openshift
      ...

    * Change OpenShift domain
      > set /files/etc/openshift/broker.conf/CLOUD_DOMAIN ose.example.com

  Saving your file:

      > save

About: Configuration files
        /etc/openshift/broker.conf - Configuration file for an OpenShift Broker
            running in production mode.
        /etc/openshift/broker-dev.conf - Configuration file for an OpenShift
            Broker running in development mode.
        /etc/openshift/console.conf - Configuration file for an OpenShift
            console running in production mode.
        /etc/openshift/console-dev.conf - Configuration file for an OpenShift
            console running in development mode.
        /etc/openshift/node.conf - Configuration file for an OpenShift node
        /etc/openshift/plugins.d/*.conf - Configuration files for OpenShift
            plugins (i.e. mcollective configuration, remote auth, dns updates)

About: Examples
   The <Test_OpenShift_Config> file contains various examples and tests.
*)
module OpenShift_Config =
    autoload xfm

(* Variable: blank_val *)
let blank_val = del /["']{2}/ "\"\""

(* View: primary_entry *)
let primary_entry = Build.key_value_line Rx.word Sep.equal Quote.any_opt

(* View: empty_entry *)
let empty_entry = Build.key_value_line Rx.word Sep.equal blank_val

(* View: lns *)
let lns = (Util.empty | Util.comment | primary_entry | empty_entry )*

(* Variable: filter *)
let filter = incl "/etc/openshift/broker.conf"
            . incl "/etc/openshift/broker-dev.conf"
            . incl "/etc/openshift/console.conf"
            . incl "/etc/openshift/resource_limits.conf"
            . incl "/etc/openshift/console-dev.conf"
            . incl "/etc/openshift/node.conf"
            . incl "/etc/openshift/plugins.d/*.conf"
            . incl "/var/www/openshift/broker/conf/broker.conf"
            . incl "/var/www/openshift/broker/conf/plugins.d/*.conf"
            . Util.stdexcl

let xfm = transform lns filter
(* vim: set ts=4  expandtab  sw=4: *)

(*
Module: OpenShift_Config
  Parses
    - /etc/openshift/broker.conf
    - /etc/openshift/broker-dev.conf
    - /etc/openshift/console.conf
    - /etc/openshift/console-dev.conf
    - /etc/openshift/plugins.d/*.conf

Author: Brian Redbeard <redbeard@dead-city.org>

About: License
   This file is licenced under the LGPL v2+, conforming to the other components
   of Augeas.

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

    * Get your current setup
      > print /files/etc/openshift
      ...

    * Change OpenShift domain
      > set /files/etc/openshift/broker.conf/CLOUD_DOMAIN ose.example.com

  Saving your file:

      > save

About: Configuration files
        /etc/openshift/broker.conf - Configuration file for an OpenShift Broker
            running in production mode.
        /etc/openshift/broker-dev.conf - Configuration file for an OpenShift
            Broker running in development mode.
        /etc/openshift/console.conf - Configuration file for an OpenShift
            console running in production mode.
        /etc/openshift/console-dev.conf - Configuration file for an OpenShift
            console running in development mode.
        /etc/openshift/plugins.d/*.conf - Configuration files for OpenShift
            plugins (i.e. mcollective configuration, remote auth, dns updates)

About: Examples
   The <Test_OpenShift_Config> file contains various examples and tests.
*)
module OpenShift_Config =
    autoload xfm

(* Variable: blank_val *)
let blank_val = del /["']{2}/ "\"\""

(* View: primary_entry *)
let primary_entry = Build.key_value_line Rx.word Sep.equal Quote.any_opt

(* View: empty_entry *)
let empty_entry = Build.key_value_line Rx.word Sep.equal blank_val

(* View: lns *)
let lns = (Util.empty | Util.comment | primary_entry | empty_entry )*

(* Variable: filter *)
let filter = incl "/etc/openshift/broker.conf"
            . incl "/etc/openshift/broker-dev.conf"
            . incl "/etc/openshift/console.conf"
            . incl "/etc/openshift/resource_limits.conf"
            . incl "/etc/openshift/console-dev.conf"
            . incl "/etc/openshift/plugins.d/*.conf"
            . incl "/var/www/openshift/broker/conf/broker.conf"
            . incl "/var/www/openshift/broker/conf/plugins.d/*.conf"
            . Util.stdexcl

let xfm = transform lns filter
(* vim: set ts=4  expandtab  sw=4: *)


Remove trailing spaces in nagioscfg.aug

Remove trailing spaces in nagioscfg.aug

(*
Module: NagiosConfig
  Parses /etc/nagios3/*.cfg

Authors: Sebastien Aperghis-Tramoni <sebastien@aperghis.net>
         Raphaël Pinson <raphink@gmail.com>

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

About: Lens Usage
  To be documented

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

module NagiosCfg =
    autoload xfm

    (* View: param_def
        define a field *)
    let param_def =
               key /[A-Za-z0-9_]+/
             . Sep.opt_space . Sep.equal
             . Sep.opt_space . store Rx.no_spaces

    (* View: param
        Params can have sub params *)
    let param =
         [ Util.indent . param_def
         . [ Sep.space . param_def ]*
         . Util.eol ]

    (* View: lns
        main structure *)
    let lns = ( Util.empty | Util.comment | param )*

    (* View: filter *)
    let filter = incl "/etc/nagios3/*.cfg"
               . Util.stdexcl

    let xfm = transform lns filter


Php: include files from Zend community edition

Fixes ticket #210

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

module PHP =
  autoload xfm

(************************************************************************
 * INI File settings
 *************************************************************************)

let comment  = IniFile.comment IniFile.comment_re IniFile.comment_default
let sep      = IniFile.sep IniFile.sep_re IniFile.sep_default
let empty    = IniFile.empty

(************************************************************************
 *                        ENTRY
 *
 * We have to remove the keyword "section" from possible entry keywords
 * otherwise it would lead to an ambiguity with the "section" label
 * since PHP allows entries outside of sections.
 *************************************************************************)
let entry    = IniFile.entry IniFile.entry_re sep comment

(************************************************************************
 *                         TITLE
 *
 * We use IniFile.title_label because there can be entries
 * outside of sections whose labels would conflict with section names
 *************************************************************************)
let title       = IniFile.title ( IniFile.record_re - ".anon" )
let record      = IniFile.record title entry

let record_anon = [ label ".anon" . ( entry | empty )+ ]

(************************************************************************
 *                         LENS & FILTER
 * There can be entries before any section
 * IniFile.entry includes comment management, so we just pass entry to lns
 *************************************************************************)
let lns    = record_anon? . record*

let filter = (incl "/etc/php*/*/*.ini")
             . (incl "/etc/php.ini")
             . (incl "/etc/php.d/*.ini")
             (* Zend Community edition *)
             . (incl "/usr/local/zend/etc/php.ini")
             . (incl "/usr/local/zend/etc/conf.d/*.ini")
             . Util.stdexcl

let xfm = transform lns filter

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

module PHP =
  autoload xfm

(************************************************************************
 * INI File settings
 *************************************************************************)

let comment  = IniFile.comment IniFile.comment_re IniFile.comment_default
let sep      = IniFile.sep IniFile.sep_re IniFile.sep_default
let empty    = IniFile.empty

(************************************************************************
 *                        ENTRY
 *
 * We have to remove the keyword "section" from possible entry keywords
 * otherwise it would lead to an ambiguity with the "section" label
 * since PHP allows entries outside of sections.
 *************************************************************************)
let entry    = IniFile.entry IniFile.entry_re sep comment

(************************************************************************
 *                         TITLE
 *
 * We use IniFile.title_label because there can be entries
 * outside of sections whose labels would conflict with section names
 *************************************************************************)
let title       = IniFile.title ( IniFile.record_re - ".anon" )
let record      = IniFile.record title entry

let record_anon = [ label ".anon" . ( entry | empty )+ ]

(************************************************************************
 *                         LENS & FILTER
 * There can be entries before any section
 * IniFile.entry includes comment management, so we just pass entry to lns
 *************************************************************************)
let lns    = record_anon? . record*

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

let xfm = transform lns filter


Automounter: exclude /etc/auto.master

Automounter: exclude /etc/auto.master

(*
Module: Automounter
  Parses automounter file based maps

Author: Dominic Cleal <dcleal@redhat.com>

About: Reference
  See autofs(5)

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to /etc/auto.*, auto_*, excluding known scripts.

About: Examples
   The <Test_Automounter> file contains various examples and tests.
*)

module Automounter =
autoload xfm

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

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

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

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

(* View: path *)
let path = /[^-+#: \t\n][^#: \t\n]*/

(* View: hostname *)
let hostname = /[^-:#\(\), \n\t]+/

(* An option label can't contain comma, comment, equals, or space *)
let optlabel = /[^,#:\(\)= \n\t]+/
let spec    = /[^,#:\(\)= \n\t][^ \n\t]*/

(* View: weight *)
let weight = Rx.integer

(* View: map_name *)
let map_name = /[^: \t\n]+/

(************************************************************************
 * Group:                 ENTRIES
 *************************************************************************)

(* View: entry_key
   Key for a map entry *)
let entry_mkey = store path

(* View: entry_path
   Path component of an entry location *)
let entry_path = [ label "path" . store path ]

(* View: entry_host
   Host component with optional weight of an entry location *)
let entry_host = [ label "host" . store hostname
                   . ( Util.del_str "(" . [ label "weight"
                       . store weight ] . Util.del_str ")" )? ]

(* View: comma_sep_list
   Parses options for filesystems *)
let comma_sep_list (l:string) =
  let value = [ label "value" . Util.del_str "=" . store Rx.neg1 ] in
    let lns = [ label l . store optlabel . value? ] in
       Build.opt_list lns Sep.comma

(* View: entry_options *)
let entry_options = Util.del_str "-" . comma_sep_list "opt" . Util.del_ws_tab

(* View: entry_location
   A single location with one or more hosts, and one path *)
let entry_location = ( entry_host . ( Sep.comma . entry_host )* )?
                       . Sep.colon . entry_path

(* View: entry_locations
   Multiple locations (each with one or more hosts), separated by spaces *)
let entry_locations = [ label "location" . counter "location"
                        . [ seq "location" . entry_location ]
                        . ( [ Util.del_ws_spc . seq "location" . entry_location ] )* ]

(* View: entry_multimount
   Parses one of many mountpoints given for a multimount line *)
let entry_multimount = entry_mkey . Util.del_ws_tab . entry_options? . entry_locations

(* View: entry_multimount_sep
   Separator for multimount entries, permits line spanning with "\" *)
let entry_multimount_sep = del /[ \t]+(\\\\[ \t]*\n[ \t]+)?/ " "

(* View: entry_multimounts
   Parses multiple mountpoints given on an entry line *)
let entry_multimounts = [ label "mount" . counter "mount"
                          . [ seq "mount" . entry_multimount ]
                          . ( [ entry_multimount_sep . seq "mount" . entry_multimount ] )* ]

(* View: entry
   A single map entry from start to finish, including multi-mounts *)
let entry = [ seq "entry" . entry_mkey . Util.del_ws_tab . entry_options?
              . ( entry_locations | entry_multimounts ) . Util.eol ]

(* View: include
   An include line starting with a "+" and a map name *)
let include = [ seq "entry" . store "+" . Util.del_opt_ws ""
                . [ label "map" . store map_name ] . Util.eol ]

(* View: lns *)
let lns = ( empty | comment | entry | include ) *

(* Variable: filter
   Exclude scripts/executable maps from here *)
let filter = incl "/etc/auto.*"
           . incl "/etc/auto_*"
           . excl "/etc/auto.master"
           . excl "/etc/auto.net"
           . excl "/etc/auto.smb"
           . Util.stdexcl

let xfm = transform lns filter

(*
Module: Automounter
  Parses automounter file based maps

Author: Dominic Cleal <dcleal@redhat.com>

About: Reference
  See autofs(5)

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to /etc/auto.*, auto_*, excluding known scripts.

About: Examples
   The <Test_Automounter> file contains various examples and tests.
*)

module Automounter =
autoload xfm

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

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

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

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

(* View: path *)
let path = /[^-+#: \t\n][^#: \t\n]*/

(* View: hostname *)
let hostname = /[^-:#\(\), \n\t]+/

(* An option label can't contain comma, comment, equals, or space *)
let optlabel = /[^,#:\(\)= \n\t]+/
let spec    = /[^,#:\(\)= \n\t][^ \n\t]*/

(* View: weight *)
let weight = Rx.integer

(* View: map_name *)
let map_name = /[^: \t\n]+/

(************************************************************************
 * Group:                 ENTRIES
 *************************************************************************)

(* View: entry_key
   Key for a map entry *)
let entry_mkey = store path

(* View: entry_path
   Path component of an entry location *)
let entry_path = [ label "path" . store path ]

(* View: entry_host
   Host component with optional weight of an entry location *)
let entry_host = [ label "host" . store hostname
                   . ( Util.del_str "(" . [ label "weight"
                       . store weight ] . Util.del_str ")" )? ]

(* View: comma_sep_list
   Parses options for filesystems *)
let comma_sep_list (l:string) =
  let value = [ label "value" . Util.del_str "=" . store Rx.neg1 ] in
    let lns = [ label l . store optlabel . value? ] in
       Build.opt_list lns Sep.comma

(* View: entry_options *)
let entry_options = Util.del_str "-" . comma_sep_list "opt" . Util.del_ws_tab

(* View: entry_location
   A single location with one or more hosts, and one path *)
let entry_location = ( entry_host . ( Sep.comma . entry_host )* )?
                       . Sep.colon . entry_path

(* View: entry_locations
   Multiple locations (each with one or more hosts), separated by spaces *)
let entry_locations = [ label "location" . counter "location"
                        . [ seq "location" . entry_location ]
                        . ( [ Util.del_ws_spc . seq "location" . entry_location ] )* ]

(* View: entry_multimount
   Parses one of many mountpoints given for a multimount line *)
let entry_multimount = entry_mkey . Util.del_ws_tab . entry_options? . entry_locations

(* View: entry_multimount_sep
   Separator for multimount entries, permits line spanning with "\" *)
let entry_multimount_sep = del /[ \t]+(\\\\[ \t]*\n[ \t]+)?/ " "

(* View: entry_multimounts
   Parses multiple mountpoints given on an entry line *)
let entry_multimounts = [ label "mount" . counter "mount"
                          . [ seq "mount" . entry_multimount ]
                          . ( [ entry_multimount_sep . seq "mount" . entry_multimount ] )* ]

(* View: entry
   A single map entry from start to finish, including multi-mounts *)
let entry = [ seq "entry" . entry_mkey . Util.del_ws_tab . entry_options?
              . ( entry_locations | entry_multimounts ) . Util.eol ]

(* View: include
   An include line starting with a "+" and a map name *)
let include = [ seq "entry" . store "+" . Util.del_opt_ws ""
                . [ label "map" . store map_name ] . Util.eol ]

(* View: lns *)
let lns = ( empty | comment | entry | include ) *

(* Variable: filter
   Exclude scripts/executable maps from here *)
let filter = incl "/etc/auto.*"
           . incl "/etc/auto_*"
           . excl "/etc/auto.net"
           . excl "/etc/auto.smb"
           . Util.stdexcl

let xfm = transform lns filter


Toml: support dos newlines

Toml: support dos newlines

(*
Module: Toml
  Parses TOML files

Author: Raphael Pinson <raphael.pinson@camptocamp.com>

About: Reference
  https://github.com/mojombo/toml/blob/master/README.md

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to TOML files.

About: Examples
   The <Test_Toml> file contains various examples and tests.
*)

module Toml =

(* Group: base definitions *)

(* View: comment
     A simple comment *)
let comment  = IniFile.comment "#" "#"

(* View: empty
     An empty line *)
let empty = Util.empty_dos

(* View: eol
     An end of line *)
let eol = Util.doseol

(* Group: value entries *)

let bare_re_noquot = (/[^][", \t\r\n]/ - "#")
let bare_re = (/[^][,\r=]/ - "#")+
let no_quot = /[^]["\r\n]*/
let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?))
let quoted = Quote.do_dquote (store (/[^"]/ . "#"* . /[^"]/))

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

let space_or_empty = [ del /[ \t\n]+/ " " ]

let comma = Util.del_str "," . (space_or_empty | comment)?
let lbrace = Util.del_str "{" . (space_or_empty | comment)?
let rbrace = Util.del_str "}"
let lbrack = Util.del_str "[" . (space_or_empty | comment)?
let rbrack = Util.del_str "]"

(* This follows the definition of 'string' at https://www.json.org/
   It's a little wider than what's allowed there as it would accept
   nonsensical \u escapes *)
let triple_dquote = Util.del_str "\"\"\""
let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote

let str_store_multi = triple_dquote . eol
                  . store /([^\\"]|\\\\["\/bfnrtu\\])*/
                  . del /\n[ \t]*/ "\n" . triple_dquote

let str_store_literal = Quote.squote . store /([^\\']|\\\\['\/bfnrtu\\])*/ . Quote.squote

let integer =
     let base10 = /[+-]?[0-9_]+/
  in let hex = /0x[A-Za-z0-9]+/
  in let oct = /0o[0-7]+/
  in let bin = /0b[01]+/
  in [ label "integer" . store (base10 | hex | oct | bin) ]

let float =
     let n = /[0-9_]+/
  in let pm = /[+-]?/
  in let z = pm . n
  in let decim = "." . n
  in let exp = /[Ee]/ . z
  in let num = z . decim | z . exp | z . decim . exp
  in let inf = pm . "inf"
  in let nan = pm . "nan"
  in [ label "float" . store (num | inf | nan) ]

let str = [ label "string" . str_store ]

let str_multi = [ label "string_multi" . str_store_multi ]

let str_literal = [ label "string_literal" . str_store_literal ]

let bool (r:regexp) = [ label "bool" . store r ]

let date_re = /[0-9]{4}-[0-9]{2}-[0-9]{2}/
let time_re = /[0-9]{1,2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?[A-Z]*/

let datetime = [ label "datetime" . store (date_re . /[T ]/ . time_re) ]
let date = [ label "date" . store date_re ]
let time = [ label "time" . store time_re ]

let norec = str | str_multi | str_literal
          | integer | float | bool /true|false/
          | datetime | date |  time

let array (value:lens) = [ label "array" . lbrack
               . ( ( Build.opt_list value comma . space_or_empty? . rbrack )
                   | rbrack ) ]

let array_norec = array norec

let rec array_rec = array (norec | array_rec)

let entry_base (value:lens) = [ label "entry" . store Rx.word . Sep.space_equal . value ]

let inline_table (value:lens) = [ label "inline_table" . lbrace
                   . ( (Build.opt_list (entry_base value) comma . space_or_empty? . rbrace)
                      | rbrace ) ]

let entry = [ label "entry" . Util.indent . store Rx.word . Sep.space_equal
            . (norec | array_rec | inline_table norec) . (eol | comment) ]

(* Group: tables *)

(* View: table_gen
     A generic table *)
let table_gen (name:string) (lbrack:string) (rbrack:string) =
     let title = Util.indent . label name
               . Util.del_str lbrack
               . store /[^]\r\n.]+(\.[^]\r\n.]+)*/
               . Util.del_str rbrack . eol
  in [ title . (entry|empty|comment)* ]

(* View: table
     A table or array of tables *)
let table = table_gen "table" "[" "]"
          | table_gen "@table" "[[" "]]"

(* Group: lens *)

(* View: lns
     The Toml lens *)
let lns = (entry | empty | comment)* . table*

(*
Module: Toml
  Parses TOML files

Author: Raphael Pinson <raphael.pinson@camptocamp.com>

About: Reference
  https://github.com/mojombo/toml/blob/master/README.md

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

About: Lens Usage
   To be documented

About: Configuration files
   This lens applies to TOML files.

About: Examples
   The <Test_Toml> file contains various examples and tests.
*)

module Toml =

(* Group: base definitions *)

(* View: comment
     A simple comment *)
let comment  = IniFile.comment "#" "#"

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

(* View: eol
     An end of line *)
let eol = Util.eol

(* Group: value entries *)

let bare_re_noquot = (/[^][", \t\r\n]/ - "#")
let bare_re = (/[^][,\r=]/ - "#")+
let no_quot = /[^]["\r\n]*/
let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?))
let quoted = Quote.do_dquote (store (/[^"]/ . "#"* . /[^"]/))

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

let space_or_empty = [ del /[ \t\n]+/ " " ]

let comma = Util.del_str "," . (space_or_empty | comment)?
let lbrace = Util.del_str "{" . (space_or_empty | comment)?
let rbrace = Util.del_str "}"
let lbrack = Util.del_str "[" . (space_or_empty | comment)?
let rbrack = Util.del_str "]"

(* This follows the definition of 'string' at https://www.json.org/
   It's a little wider than what's allowed there as it would accept
   nonsensical \u escapes *)
let triple_dquote = Util.del_str "\"\"\""
let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote

let str_store_multi = triple_dquote . eol
                  . store /([^\\"]|\\\\["\/bfnrtu\\])*/
                  . del /\n[ \t]*/ "\n" . triple_dquote

let str_store_literal = Quote.squote . store /([^\\']|\\\\['\/bfnrtu\\])*/ . Quote.squote

let integer =
     let base10 = /[+-]?[0-9_]+/
  in let hex = /0x[A-Za-z0-9]+/
  in let oct = /0o[0-7]+/
  in let bin = /0b[01]+/
  in [ label "integer" . store (base10 | hex | oct | bin) ]

let float =
     let n = /[0-9_]+/
  in let pm = /[+-]?/
  in let z = pm . n
  in let decim = "." . n
  in let exp = /[Ee]/ . z
  in let num = z . decim | z . exp | z . decim . exp
  in let inf = pm . "inf"
  in let nan = pm . "nan"
  in [ label "float" . store (num | inf | nan) ]

let str = [ label "string" . str_store ]

let str_multi = [ label "string_multi" . str_store_multi ]

let str_literal = [ label "string_literal" . str_store_literal ]

let bool (r:regexp) = [ label "bool" . store r ]

let date_re = /[0-9]{4}-[0-9]{2}-[0-9]{2}/
let time_re = /[0-9]{1,2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?[A-Z]*/

let datetime = [ label "datetime" . store (date_re . /[T ]/ . time_re) ]
let date = [ label "date" . store date_re ]
let time = [ label "time" . store time_re ]

let norec = str | str_multi | str_literal
          | integer | float | bool /true|false/
          | datetime | date |  time

let array (value:lens) = [ label "array" . lbrack
               . ( ( Build.opt_list value comma . space_or_empty? . rbrack )
                   | rbrack ) ]

let array_norec = array norec

let rec array_rec = array (norec | array_rec)

let entry_base (value:lens) = [ label "entry" . store Rx.word . Sep.space_equal . value ]

let inline_table (value:lens) = [ label "inline_table" . lbrace
                   . ( (Build.opt_list (entry_base value) comma . space_or_empty? . rbrace)
                      | rbrace ) ]

let entry = [ label "entry" . Util.indent . store Rx.word . Sep.space_equal
            . (norec | array_rec | inline_table norec) . (eol | comment) ]

(* Group: tables *)

(* View: table_gen
     A generic table *)
let table_gen (name:string) (lbrack:string) (rbrack:string) =
     let title = Util.indent . label name
               . Util.del_str lbrack
               . store /[^]\r\n.]+(\.[^]\r\n.]+)*/
               . Util.del_str rbrack . eol
  in [ title . (entry|empty|comment)* ]

(* View: table
     A table or array of tables *)
let table = table_gen "table" "[" "]"
          | table_gen "@table" "[[" "]]"

(* Group: lens *)

(* View: lns
     The Toml lens *)
let lns = (entry | empty | comment)* . table*


vsftpd.aug: Add require_ssl_reuse option

(* Parse vsftpd.conf *)
module Vsftpd =
  autoload xfm

(* The code in parseconf.c does not seem to allow for trailing whitespace *)
(* in the config file                                                     *)
let eol = Util.del_str "\n"
let empty = Util.empty
let comment = Util.comment

let bool_option_re = /anonymous_enable|local_enable|pasv_enable|port_enable|chroot_local_user|write_enable|anon_upload_enable|anon_mkdir_write_enable|anon_other_write_enable|chown_uploads|connect_from_port_20|xferlog_enable|dirmessage_enable|anon_world_readable_only|async_abor_enable|ascii_upload_enable|ascii_download_enable|one_process_model|xferlog_std_format|pasv_promiscuous|deny_email_enable|chroot_list_enable|setproctitle_enable|text_userdb_names|ls_recurse_enable|log_ftp_protocol|guest_enable|userlist_enable|userlist_deny|use_localtime|check_shell|hide_ids|listen|port_promiscuous|passwd_chroot_enable|no_anon_password|tcp_wrappers|use_sendfile|force_dot_files|listen_ipv6|dual_log_enable|syslog_enable|background|virtual_use_local_privs|session_support|download_enable|dirlist_enable|chmod_enable|secure_email_list_enable|run_as_launching_user|no_log_lock|ssl_enable|allow_anon_ssl|force_local_logins_ssl|force_local_data_ssl|ssl_sslv2|ssl_sslv3|ssl_tlsv1|tilde_user_enable|force_anon_logins_ssl|force_anon_data_ssl|mdtm_write|lock_upload_files|pasv_addr_resolve|debug_ssl|require_cert|validate_cert|require_ssl_reuse/

let uint_option_re = /accept_timeout|connect_timeout|local_umask|anon_umask|ftp_data_port|idle_session_timeout|data_connection_timeout|pasv_min_port|pasv_max_port|anon_max_rate|local_max_rate|listen_port|max_clients|file_open_mode|max_per_ip|trans_chunk_size|delay_failed_login|delay_successful_login|max_login_fails|chown_upload_mode/

let str_option_re = /secure_chroot_dir|ftp_username|chown_username|xferlog_file|vsftpd_log_file|message_file|nopriv_user|ftpd_banner|banned_email_file|chroot_list_file|pam_service_name|guest_username|userlist_file|anon_root|local_root|banner_file|pasv_address|listen_address|user_config_dir|listen_address6|cmds_allowed|hide_file|deny_file|user_sub_token|email_password_file|rsa_cert_file|dsa_cert_file|ssl_ciphers|rsa_private_key_file|dsa_private_key_file|ca_certs_file/

let bool_value_re = /[yY][eE][sS]|[tT][rR][uU][eE]|1|[nN][oO]|[fF][aA][lL][sS][eE]|0/

let option (k:regexp) (v:regexp) = [ key k . Util.del_str "=" . store v . eol ]

let bool_option = option bool_option_re bool_value_re

let str_option = option str_option_re /[^\n]+/

let uint_option = option uint_option_re /[0-9]+/

let lns = (bool_option|str_option|uint_option|comment|empty)*

let filter = (incl "/etc/vsftpd.conf") . (incl "/etc/vsftpd/vsftpd.conf")

let xfm = transform lns filter

(* Parse vsftpd.conf *)
module Vsftpd =
  autoload xfm

(* The code in parseconf.c does not seem to allow for trailing whitespace *)
(* in the config file                                                     *)
let eol = Util.del_str "\n"
let empty = Util.empty
let comment = Util.comment

let bool_option_re = /anonymous_enable|local_enable|pasv_enable|port_enable|chroot_local_user|write_enable|anon_upload_enable|anon_mkdir_write_enable|anon_other_write_enable|chown_uploads|connect_from_port_20|xferlog_enable|dirmessage_enable|anon_world_readable_only|async_abor_enable|ascii_upload_enable|ascii_download_enable|one_process_model|xferlog_std_format|pasv_promiscuous|deny_email_enable|chroot_list_enable|setproctitle_enable|text_userdb_names|ls_recurse_enable|log_ftp_protocol|guest_enable|userlist_enable|userlist_deny|use_localtime|check_shell|hide_ids|listen|port_promiscuous|passwd_chroot_enable|no_anon_password|tcp_wrappers|use_sendfile|force_dot_files|listen_ipv6|dual_log_enable|syslog_enable|background|virtual_use_local_privs|session_support|download_enable|dirlist_enable|chmod_enable|secure_email_list_enable|run_as_launching_user|no_log_lock|ssl_enable|allow_anon_ssl|force_local_logins_ssl|force_local_data_ssl|ssl_sslv2|ssl_sslv3|ssl_tlsv1|tilde_user_enable|force_anon_logins_ssl|force_anon_data_ssl|mdtm_write|lock_upload_files|pasv_addr_resolve|debug_ssl|require_cert|validate_cert/

let uint_option_re = /accept_timeout|connect_timeout|local_umask|anon_umask|ftp_data_port|idle_session_timeout|data_connection_timeout|pasv_min_port|pasv_max_port|anon_max_rate|local_max_rate|listen_port|max_clients|file_open_mode|max_per_ip|trans_chunk_size|delay_failed_login|delay_successful_login|max_login_fails|chown_upload_mode/

let str_option_re = /secure_chroot_dir|ftp_username|chown_username|xferlog_file|vsftpd_log_file|message_file|nopriv_user|ftpd_banner|banned_email_file|chroot_list_file|pam_service_name|guest_username|userlist_file|anon_root|local_root|banner_file|pasv_address|listen_address|user_config_dir|listen_address6|cmds_allowed|hide_file|deny_file|user_sub_token|email_password_file|rsa_cert_file|dsa_cert_file|ssl_ciphers|rsa_private_key_file|dsa_private_key_file|ca_certs_file/

let bool_value_re = /[yY][eE][sS]|[tT][rR][uU][eE]|1|[nN][oO]|[fF][aA][lL][sS][eE]|0/

let option (k:regexp) (v:regexp) = [ key k . Util.del_str "=" . store v . eol ]

let bool_option = option bool_option_re bool_value_re

let str_option = option str_option_re /[^\n]+/

let uint_option = option uint_option_re /[0-9]+/

let lns = (bool_option|str_option|uint_option|comment|empty)*

let filter = (incl "/etc/vsftpd.conf") . (incl "/etc/vsftpd/vsftpd.conf")

let xfm = transform lns filter


Shellvars: added SuSE sysconfig puppet files

For SuSE systems, added /etc/sysconfig/{puppet,puppetmaster} to lens.

(* Generic lens for shell-script config files like the ones found *)
(* in /etc/sysconfig                                              *)
module Shellvars =
  autoload xfm

  let eol = Util.eol

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let eq = Util.del_str "="
  let comment = Util.comment
  let empty   = Util.empty
  let xchgs   = Build.xchgs

  let char  = /[^() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  let bquot = /`[^`\n]*`/

  (* 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 (char+ | dquot) 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 (char* | dquot | squot | bquot | empty_array)

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

  let var_action (name:string) =
    [ xchgs name ("@" . name) . Util.del_ws_spc . store key_re . eol ]

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

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

  let lns = (comment | empty | source | kv | unset | bare_export) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let filter_sysconfig =
      sc_incl "atd" .
      sc_incl "authconfig" .
      sc_incl "autofs" .
      sc_incl "clock" .
      sc_incl "cpuspeed" .
      sc_incl "crond" .
      sc_incl "crontab" .
      sc_incl "desktop" .
      sc_incl "firstboot" .
      sc_incl "grub" .
      sc_incl "hsqldb" .
      sc_incl "httpd" .
      sc_incl "i18n" .
      sc_incl "init" .
      sc_incl "iptables-config" .
      sc_incl "irda" .
      sc_incl "irqbalance" .
      sc_incl "kdump" .
      sc_incl "keyboard" .
      sc_incl "kudzu" .
      sc_incl "libvirtd" .
      sc_incl "lircd" .
      sc_incl "nasd" .
      sc_incl "netconsole" .
      sc_incl "network" .
      sc_incl "nfs" .
      sc_incl "ntpd" .
      sc_incl "prelink" .
      sc_incl "puppet" .
      sc_incl "puppetmaster" .
      sc_incl "readonly-root" .
      sc_incl "rsyslog" .
      sc_incl "samba" .
      sc_incl "saslauthd" .
      sc_incl "selinux" .
      sc_incl "sendmail" .
      sc_incl "smartmontools" .
      sc_incl "spamassassin" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_ifcfg   = incl "/etc/sysconfig/network-scripts/ifcfg-*"
                     . incl "/etc/sysconfig/network/ifcfg-*"
  let filter_default = incl "/etc/default/*"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"

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

  let xfm = transform lns filter

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

(* Generic lens for shell-script config files like the ones found *)
(* in /etc/sysconfig                                              *)
module Shellvars =
  autoload xfm

  let eol = Util.eol

  let key_re = /[A-Za-z0-9_]+(\[[0-9]+\])?/ - "unset" - "export"
  let eq = Util.del_str "="
  let comment = Util.comment
  let empty   = Util.empty
  let xchgs   = Build.xchgs

  let char  = /[^() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  let bquot = /`[^`\n]*`/

  (* 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 (char+ | dquot) 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 (char* | dquot | squot | bquot | empty_array)

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

  let var_action (name:string) =
    [ xchgs name ("@" . name) . Util.del_ws_spc . store key_re . eol ]

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

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

  let lns = (comment | empty | source | kv | unset | bare_export) *

  let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n))
  let filter_sysconfig =
      sc_incl "atd" .
      sc_incl "authconfig" .
      sc_incl "autofs" .
      sc_incl "clock" .
      sc_incl "cpuspeed" .
      sc_incl "crond" .
      sc_incl "crontab" .
      sc_incl "desktop" .
      sc_incl "firstboot" .
      sc_incl "grub" .
      sc_incl "hsqldb" .
      sc_incl "httpd" .
      sc_incl "i18n" .
      sc_incl "init" .
      sc_incl "iptables-config" .
      sc_incl "irda" .
      sc_incl "irqbalance" .
      sc_incl "kdump" .
      sc_incl "keyboard" .
      sc_incl "kudzu" .
      sc_incl "libvirtd" .
      sc_incl "lircd" .
      sc_incl "nasd" .
      sc_incl "netconsole" .
      sc_incl "network" .
      sc_incl "nfs" .
      sc_incl "ntpd" .
      sc_incl "prelink" .
      sc_incl "readonly-root" .
      sc_incl "rsyslog" .
      sc_incl "samba" .
      sc_incl "saslauthd" .
      sc_incl "selinux" .
      sc_incl "sendmail" .
      sc_incl "smartmontools" .
      sc_incl "spamassassin" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_ifcfg   = incl "/etc/sysconfig/network-scripts/ifcfg-*"
                     . incl "/etc/sysconfig/network/ifcfg-*"
  let filter_default = incl "/etc/default/*"
  let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                     . incl "/etc/cron-apt/config"
                     . incl "/etc/environment"

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

  let xfm = transform lns filter

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


Logrotate: small fixes

Logrotate: small fixes

* recognize 'yearly' schedule
* allow whitespaces around { and }

(* Logrotate module for Augeas                *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(* Patches from:                              *)
(*   Sean Millichamp <sean@bruenor.org>       *)
(*                                            *)
(* Supported :                                *)
(*   - defaults                               *)
(*   - rules                                  *)
(*   - (pre|post)rotate entries               *)
(*                                            *)
(* Todo :                                     *)
(*                                            *)

module Logrotate =
   autoload xfm

   let sep_spc = Util.del_ws_spc
   let eol = Util.del_str "\n"
   let num = /[0-9]+/
   let word = /[^,# \n\t{}]+/

   (* define comments and empty lines *)
   let comment (indent:string) = [ label "comment" . del /[ \t]*/ indent . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . eol ]
   let empty   = [ del /[ \t]*\n/ "\n" ]

   (* Useful functions *)

   let list_item = [ sep_spc . key /[^\/+,# \n\t{}]+/ ]
   let select_to_eol (kw:string) (select:regexp) (indent:string) = [ del /[ \t]*/ indent . label kw . store select . eol ]
   let value_to_eol (kw:string) (value:regexp) (indent:string )  = [ del /[ \t]*/ indent . key kw . sep_spc . store value . eol ]
   let flag_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . eol ]
   let list_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . list_item+ . eol ]

   (* Defaults *)

   let create (indent:string ) = [ del /[ \t]*/ indent . key "create" .
                       ( sep_spc . [ label "mode" . store num ] . sep_spc .
		       [ label "owner" . store word ] . sep_spc .
		       [ label "group" . store word ])?
		    . eol ]

   let tabooext (indent:string) = [ del /[ \t]*/ indent . key "tabooext" . ( sep_spc . store /\+/ )? . list_item+ . eol ]

   let attrs (indent:string) = select_to_eol "schedule" /(daily|weekly|monthly|yearly)/ indent
                | value_to_eol "rotate" num indent
		| create indent
		| flag_to_eol "nocreate" indent
		| value_to_eol "include" word indent
		| select_to_eol "missingok" /(no)?missingok/ indent
		| select_to_eol "compress" /(no)?compress/ indent
		| select_to_eol "delaycompress" /(no)?delaycompress/ indent
		| select_to_eol "ifempty" /(not)?ifempty/ indent
		| select_to_eol "sharedscripts" /(no)?sharedscripts/ indent
		| value_to_eol "size" word indent
		| tabooext indent
		| value_to_eol "olddir" word indent
		| flag_to_eol "noolddir" indent
		| value_to_eol "mail" word indent
		| flag_to_eol "mailfirst" indent
		| flag_to_eol "maillast" indent
		| flag_to_eol "nomail" indent
		| value_to_eol "errors" word indent
		| value_to_eol "extension" word indent
		| select_to_eol "dateext" /(no)?dateext/ indent
		| value_to_eol "compresscmd" word indent
		| value_to_eol "uncompresscmd" word indent
		| value_to_eol "compressext" word indent
		| list_to_eol "compressoptions" indent
		| select_to_eol "copy" /(no)?copy/ indent
		| select_to_eol "copytruncate" /(no)?copytruncate/ indent
		| value_to_eol "maxage" num indent
		| value_to_eol "minsize" num indent
		| select_to_eol "shred" /(no)?shred/ indent
		| value_to_eol "shredcycles" num indent
		| value_to_eol "start" num indent

   (* Define hooks *)

   let hook_lines = store ( ( /.*/ . "\n") - /[ \t]*endscript[ \t]*\n/ )*

   let hook_func (func_type:string) = [
       del /[ \t]*/ "\t" . key func_type . eol .
       hook_lines .
       del /[ \t]*endscript\n/ "\tendscript\n" ]

   let hooks = hook_func "postrotate"
             | hook_func "prerotate"
             | hook_func "firstaction"
             | hook_func "lastaction"

   (* Define rule *)

   let body = del /\{[ \t]*\n/ "{\n"
                       . ( comment "\t" | attrs "\t" | hooks | empty )*
                       . del /[ \t]*\}[ \t]*\n/ "}\n"

   let rule =
     [ label "rule" .
         [ label "file" . store word ] .
	 [ del /[ \t]+/ " " . label "file" . store word ]* .
	 del /[ \t\n]*/ " " . body ]

   let lns = ( comment "" | empty | attrs "" | rule )*

   let filter = incl "/etc/logrotate.d/*"
              . incl "/etc/logrotate.conf"
	      . Util.stdexcl

   let xfm = transform lns filter

(* Logrotate module for Augeas                *)
(* Author: Raphael Pinson <raphink@gmail.com> *)
(* Patches from:                              *)
(*   Sean Millichamp <sean@bruenor.org>       *)
(*                                            *)
(* Supported :                                *)
(*   - defaults                               *)
(*   - rules                                  *)
(*   - (pre|post)rotate entries               *)
(*                                            *)
(* Todo :                                     *)
(*                                            *)

module Logrotate =
   autoload xfm

   let sep_spc = Util.del_ws_spc
   let eol = Util.del_str "\n"
   let num = /[0-9]+/
   let word = /[^,# \n\t{}]+/

   (* define comments and empty lines *)
   let comment (indent:string) = [ label "comment" . del /[ \t]*/ indent . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . eol ]
   let empty   = [ del /[ \t]*\n/ "\n" ]

   (* Useful functions *)

   let list_item = [ sep_spc . key /[^\/+,# \n\t{}]+/ ]
   let select_to_eol (kw:string) (select:regexp) (indent:string) = [ del /[ \t]*/ indent . label kw . store select . eol ]
   let value_to_eol (kw:string) (value:regexp) (indent:string )  = [ del /[ \t]*/ indent . key kw . sep_spc . store value . eol ]
   let flag_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . eol ]
   let list_to_eol (kw:string) (indent:string)                   = [ del /[ \t]*/ indent . key kw . list_item+ . eol ]

   (* Defaults *)

   let create (indent:string ) = [ del /[ \t]*/ indent . key "create" .
                       ( sep_spc . [ label "mode" . store num ] . sep_spc .
		       [ label "owner" . store word ] . sep_spc .
		       [ label "group" . store word ])?
		    . eol ]

   let tabooext (indent:string) = [ del /[ \t]*/ indent . key "tabooext" . ( sep_spc . store /\+/ )? . list_item+ . eol ]

   let attrs (indent:string) = select_to_eol "schedule" /(daily|weekly|monthly)/ indent
                | value_to_eol "rotate" num indent
		| create indent
		| flag_to_eol "nocreate" indent
		| value_to_eol "include" word indent
		| select_to_eol "missingok" /(no)?missingok/ indent
		| select_to_eol "compress" /(no)?compress/ indent
		| select_to_eol "delaycompress" /(no)?delaycompress/ indent
		| select_to_eol "ifempty" /(not)?ifempty/ indent
		| select_to_eol "sharedscripts" /(no)?sharedscripts/ indent
		| value_to_eol "size" word indent
		| tabooext indent
		| value_to_eol "olddir" word indent
		| flag_to_eol "noolddir" indent
		| value_to_eol "mail" word indent
		| flag_to_eol "mailfirst" indent
		| flag_to_eol "maillast" indent
		| flag_to_eol "nomail" indent
		| value_to_eol "errors" word indent
		| value_to_eol "extension" word indent
		| select_to_eol "dateext" /(no)?dateext/ indent
		| value_to_eol "compresscmd" word indent
		| value_to_eol "uncompresscmd" word indent
		| value_to_eol "compressext" word indent
		| list_to_eol "compressoptions" indent
		| select_to_eol "copy" /(no)?copy/ indent
		| select_to_eol "copytruncate" /(no)?copytruncate/ indent
		| value_to_eol "maxage" num indent
		| value_to_eol "minsize" num indent
		| select_to_eol "shred" /(no)?shred/ indent
		| value_to_eol "shredcycles" num indent
		| value_to_eol "start" num indent

   (* Define hooks *)

   let hook_lines = store ( ( /.*/ . "\n") - /[ \t]*endscript[ \t]*\n/ )*

   let hook_func (func_type:string) = [
       del /[ \t]*/ "\t" . key func_type . eol .
       hook_lines .
       del /[ \t]*endscript\n/ "\tendscript\n" ]

   let hooks = hook_func "postrotate"
             | hook_func "prerotate"
             | hook_func "firstaction"
             | hook_func "lastaction"

   (* Define rule *)

   let body = Util.del_str "{\n"
                       . ( comment "\t" | attrs "\t" | hooks | empty )*
                       . Util.del_str "}\n"

   let rule =
     [ label "rule" .
         [ label "file" . store word ] .
	 [ del /[ \t]+/ " " . label "file" . store word ]* .
	 del /[ \t\n]*/ " " . body ]

   let lns = ( comment "" | empty | attrs "" | rule )*

   let filter = incl "/etc/logrotate.d/*"
              . incl "/etc/logrotate.conf"
	      . Util.stdexcl

   let xfm = transform lns filter


Modprobe: Suse includes

Modprobe: Suse includes

* lenses/modprobe.aug: included /etc/modprobe.conf.local

(*
Module: Modprobe
  Parses /etc/modprobe.conf and /etc/modprobe.d/*
*)
module Modprobe =
autoload xfm

let comment = Util.comment
let empty = Util.empty
let eol = Util.eol | Util.comment

(* modprobe.conf allows continuing a line by ending it with backslash +
   newline; the backslash + newline token is suppressed We handle an
   approximation of that by classifying backslash + newline as a
   separator.
*)

(* A separator is either whitespace or \ followed by newline *)
let sep_ch = /[ \t]|\\\\\n/
(* Anything that's not a separator is part of a token *)
let tok_ch = /[^ \t\n#\\]|\\\\[^ \t\n]/

let spc = del sep_ch+ " "
let token = store tok_ch+
let indent = Util.del_opt_ws ""

let cmd (n:regexp) = key n . spc
let arg (n:string) = [ label n . token ]
let token_to_eol = store (tok_ch . /([^#\n\\]|\\\\\n)*/ . tok_ch | tok_ch)

let options =
  let opt_ch = /[A-Za-z0-9_]/ in
  let option = [ spc . key opt_ch+ . (del /=/ "=" . token)? ] in
    [ cmd "options" . token . option* . eol ]

let entry = [ cmd "alias" . token . spc . arg "modulename" . eol ]
  | [ cmd "include" . token . eol ]
  | options
  | [ cmd /install|remove/ . token_to_eol . eol ]
  | [ cmd "blacklist" . token . eol ]
  | [ cmd "config" . store /binary_indexes|yes|no/ ]

let lns = (comment|empty|entry)*

let filter = (incl "/etc/modprobe.conf") .
  (incl "/etc/modprobe.d/*").
  (incl "/etc/modprobe.conf.local").
  Util.stdexcl

let xfm = transform lns filter

(*
Module: Modprobe
  Parses /etc/modprobe.conf and /etc/modprobe.d/*
*)
module Modprobe =
autoload xfm

let comment = Util.comment
let empty = Util.empty
let eol = Util.eol | Util.comment

(* modprobe.conf allows continuing a line by ending it with backslash +
   newline; the backslash + newline token is suppressed We handle an
   approximation of that by classifying backslash + newline as a
   separator.
*)

(* A separator is either whitespace or \ followed by newline *)
let sep_ch = /[ \t]|\\\\\n/
(* Anything that's not a separator is part of a token *)
let tok_ch = /[^ \t\n#\\]|\\\\[^ \t\n]/

let spc = del sep_ch+ " "
let token = store tok_ch+
let indent = Util.del_opt_ws ""

let cmd (n:regexp) = key n . spc
let arg (n:string) = [ label n . token ]
let token_to_eol = store (tok_ch . /([^#\n\\]|\\\\\n)*/ . tok_ch | tok_ch)

let options =
  let opt_ch = /[A-Za-z0-9_]/ in
  let option = [ spc . key opt_ch+ . (del /=/ "=" . token)? ] in
    [ cmd "options" . token . option* . eol ]

let entry = [ cmd "alias" . token . spc . arg "modulename" . eol ]
  | [ cmd "include" . token . eol ]
  | options
  | [ cmd /install|remove/ . token_to_eol . eol ]
  | [ cmd "blacklist" . token . eol ]
  | [ cmd "config" . store /binary_indexes|yes|no/ ]

let lns = (comment|empty|entry)*

let filter = (incl "/etc/modprobe.conf") .
  (incl "/etc/modprobe.d/*").
  Util.stdexcl

let xfm = transform lns filter


Add two files found on OpenBSD to the simplevars lens.

(*
Module: Simplevars
  Parses simple key = value conffiles

Author: Raphael Pinson <raphink@gmail.com>

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

About: Lens Usage
   To be documented

About: Examples
   The <Test_Simplevars> file contains various examples and tests.
*)

module Simplevars =

autoload xfm

(* Variable: to_comment_re
   The regexp to match the value *)
let to_comment_re =
     let to_comment_squote = /'[^\n']*'/
  in let to_comment_dquote = /"[^\n"]*"/
  in let to_comment_noquote = /[^\n \t'"#][^\n#]*[^\n \t#]|[^\n \t'"#]/
  in to_comment_squote | to_comment_dquote | to_comment_noquote

(* View: entry *)
let entry = Build.key_value Rx.word Sep.space_equal
            (store to_comment_re . (Util.eol|Util.comment_eol))

(* View: lns *)
let lns = (Util.empty | Util.comment | entry)*

(* Variable: filter *)
let filter = incl "/etc/kernel-img.conf"
           . incl "/etc/kerneloops.conf"
           . incl "/etc/updatedb.conf"
           . incl "/etc/wgetrc"
           . incl "/etc/zabbix/*.conf"
           . incl "/etc/audit/auditd.conf"
           . incl "/etc/mixerctl.conf"
           . incl "/etc/wsconsctlctl.conf"

let xfm = transform lns filter

(*
Module: Simplevars
  Parses simple key = value conffiles

Author: Raphael Pinson <raphink@gmail.com>

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

About: Lens Usage
   To be documented

About: Examples
   The <Test_Simplevars> file contains various examples and tests.
*)

module Simplevars =

autoload xfm

(* Variable: to_comment_re
   The regexp to match the value *)
let to_comment_re =
     let to_comment_squote = /'[^\n']*'/
  in let to_comment_dquote = /"[^\n"]*"/
  in let to_comment_noquote = /[^\n \t'"#][^\n#]*[^\n \t#]|[^\n \t'"#]/
  in to_comment_squote | to_comment_dquote | to_comment_noquote

(* View: entry *)
let entry = Build.key_value Rx.word Sep.space_equal
            (store to_comment_re . (Util.eol|Util.comment_eol))

(* View: lns *)
let lns = (Util.empty | Util.comment | entry)*

(* Variable: filter *)
let filter = incl "/etc/kernel-img.conf"
           . incl "/etc/kerneloops.conf"
           . incl "/etc/updatedb.conf"
           . incl "/etc/wgetrc"
           . incl "/etc/zabbix/*.conf"
           . incl "/etc/audit/auditd.conf"

let xfm = transform lns filter