Rabbitmq: Adding some missing simple options

(*
Module: Rabbitmq
  Parses Rabbitmq configuration files

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

About: Reference
  This lens tries to keep as close as possible to `http://www.rabbitmq.com/configure.html` where possible.

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 Rabbitmq configuration files. See <filter>.

About: Examples
   The <Test_Rabbitmq> file contains various examples and tests.
*)
module Rabbitmq =

autoload xfm

(* View: listeners
     A tcp/ssl listener *)
let listeners =
     let value = Erlang.make_value Erlang.integer
               | Erlang.tuple Erlang.quoted Erlang.integer
  in Erlang.list /(tcp|ssl)_listeners/ value

(* View: ssl_options
    (Incomplete) list of SSL options *)
let ssl_options =
     let option = Erlang.value /((ca)?cert|key)file/ Erlang.path
                | Erlang.value "verify" Erlang.bare
                | Erlang.value "verify_fun" Erlang.boolean
                | Erlang.value /fail_if_no_peer_cert|reuse_sessions/ Erlang.boolean
                | Erlang.value "depth" Erlang.integer
                | Erlang.value "password" Erlang.quoted
  in Erlang.list "ssl_options" option

(* View: disk_free_limit *)
let disk_free_limit =
     let value = Erlang.integer | Erlang.tuple Erlang.bare Erlang.decimal
  in Erlang.value "disk_free_limit" value

(* View: log_levels *)
let log_levels =
     let category = Erlang.tuple Erlang.bare Erlang.bare
  in Erlang.list "log_levels" category

(* View: cluster_nodes
     Can be a tuple `(nodes, node_type)` or simple `nodes` *)
let cluster_nodes =
     let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted)
  in let value = Erlang.tuple nodes Erlang.bare
               | nodes
  in Erlang.value "cluster_nodes" value

(* View: cluster_partition_handling
     Can be single value or
     `{pause_if_all_down, [nodes], ignore | autoheal}` *)
let cluster_partition_handling =
     let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted)
  in let value = Erlang.tuple3 Erlang.bare nodes Erlang.bare
               | Erlang.bare
  in Erlang.value "cluster_partition_handling" value

(* View: tcp_listen_options *)
let tcp_listen_options =
     let value = Erlang.make_value Erlang.bare
               | Erlang.tuple Erlang.bare Erlang.bare
  in Erlang.list "tcp_listen_options" value

(* View: parameters
     Top-level parameters for the lens *)
let parameters = listeners
               | ssl_options
               | disk_free_limit
               | log_levels
               | Erlang.value "vm_memory_high_watermark" Erlang.decimal
               | Erlang.value "vm_memory_high_watermark_paging_ratio" Erlang.decimal
               | Erlang.value "frame_max" Erlang.integer
               | Erlang.value "heartbeat" Erlang.integer
               | Erlang.value /default_(vhost|user|pass)/ Erlang.glob
               | Erlang.value_list "default_user_tags" Erlang.bare
               | Erlang.value_list "default_permissions" Erlang.glob
               | cluster_nodes
               | Erlang.value_list "server_properties" Erlang.bare
               | Erlang.value "collect_statistics" Erlang.bare
               | Erlang.value "collect_statistics_interval" Erlang.integer
               | Erlang.value_list "auth_mechanisms" Erlang.quoted
               | Erlang.value_list "auth_backends" Erlang.bare
               | Erlang.value "delegate_count" Erlang.integer
               | Erlang.value_list "trace_vhosts" Erlang.bare
               | tcp_listen_options
               | Erlang.value "hipe_compile" Erlang.boolean
               | Erlang.value "msg_store_index_module" Erlang.bare
               | Erlang.value "backing_queue_module" Erlang.bare
               | Erlang.value "msg_store_file_size_limit" Erlang.integer
               | Erlang.value "queue_index_max_journal_entries" Erlang.integer
               | Erlang.value "queue_index_embed_msgs_below" Erlang.integer
               | cluster_partition_handling
               | Erlang.value "handshake_timeout" Erlang.integer
               | Erlang.value "ssl_handshake_timeout" Erlang.integer
               | Erlang.value "channel_max" Erlang.integer
               | Erlang.value_list "loopback_users" Erlang.glob
               | Erlang.value "reverse_dns_lookups" Erlang.boolean
               | Erlang.value "cluster_keepalive_interval" Erlang.integer
               | Erlang.value "mnesia_table_loading_timeout" Erlang.integer

(* View: rabbit
    The rabbit <Erlang.application> config *)
let rabbit = Erlang.application "rabbit" parameters

(* View: lns
    A top-level <Erlang.config> *)
let lns = Erlang.config rabbit

(* Variable: filter *)
let filter = incl "/etc/rabbitmq/rabbitmq.config"

let xfm = transform lns filter

(*
Module: Rabbitmq
  Parses Rabbitmq configuration files

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

About: Reference
  This lens tries to keep as close as possible to `http://www.rabbitmq.com/configure.html` where possible.

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 Rabbitmq configuration files. See <filter>.

About: Examples
   The <Test_Rabbitmq> file contains various examples and tests.
*)
module Rabbitmq =

autoload xfm

(* View: listeners
     A tcp/ssl listener *)
let listeners =
     let value = Erlang.make_value Erlang.integer
               | Erlang.tuple Erlang.quoted Erlang.integer
  in Erlang.list /(tcp|ssl)_listeners/ value

(* View: ssl_options
    (Incomplete) list of SSL options *)
let ssl_options =
     let option = Erlang.value /((ca)?cert|key)file/ Erlang.path
                | Erlang.value "verify" Erlang.bare
                | Erlang.value "verify_fun" Erlang.boolean
                | Erlang.value /fail_if_no_peer_cert|reuse_sessions/ Erlang.boolean
                | Erlang.value "depth" Erlang.integer
                | Erlang.value "password" Erlang.quoted
  in Erlang.list "ssl_options" option

(* View: disk_free_limit *)
let disk_free_limit =
     let value = Erlang.integer | Erlang.tuple Erlang.bare Erlang.decimal
  in Erlang.value "disk_free_limit" value

(* View: log_levels *)
let log_levels =
     let category = Erlang.tuple Erlang.bare Erlang.bare
  in Erlang.list "log_levels" category

(* View: cluster_nodes
     Can be a tuple `(nodes, node_type)` or simple `nodes` *)
let cluster_nodes =
     let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted)
  in let value = Erlang.tuple nodes Erlang.bare
               | nodes
  in Erlang.value "cluster_nodes" value

(* View: cluster_partition_handling
     Can be single value or
     `{pause_if_all_down, [nodes], ignore | autoheal}` *)
let cluster_partition_handling =
     let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted)
  in let value = Erlang.tuple3 Erlang.bare nodes Erlang.bare
               | Erlang.bare
  in Erlang.value "cluster_partition_handling" value

(* View: tcp_listen_options *)
let tcp_listen_options =
     let value = Erlang.make_value Erlang.bare
               | Erlang.tuple Erlang.bare Erlang.bare
  in Erlang.list "tcp_listen_options" value

(* View: parameters
     Top-level parameters for the lens *)
let parameters = listeners
               | ssl_options
               | disk_free_limit
               | log_levels
               | Erlang.value "vm_memory_high_watermark" Erlang.decimal
               | Erlang.value "frame_max" Erlang.integer
               | Erlang.value "heartbeat" Erlang.integer
               | Erlang.value /default_(vhost|user|pass)/ Erlang.glob
               | Erlang.value_list "default_user_tags" Erlang.bare
               | Erlang.value_list "default_permissions" Erlang.glob
               | cluster_nodes
               | Erlang.value_list "server_properties" Erlang.bare
               | Erlang.value "collect_statistics" Erlang.bare
               | Erlang.value "collect_statistics_interval" Erlang.integer
               | Erlang.value_list "auth_mechanisms" Erlang.quoted
               | Erlang.value_list "auth_backends" Erlang.bare
               | Erlang.value "delegate_count" Erlang.integer
               | Erlang.value_list "trace_vhosts" Erlang.bare
               | tcp_listen_options
               | Erlang.value "hipe_compile" Erlang.boolean
               | Erlang.value "msg_store_index_module" Erlang.bare
               | Erlang.value "backing_queue_module" Erlang.bare
               | Erlang.value "msg_store_file_size_limit" Erlang.integer
               | Erlang.value "queue_index_max_journal_entries" Erlang.integer
               | cluster_partition_handling

(* View: rabbit
    The rabbit <Erlang.application> config *)
let rabbit = Erlang.application "rabbit" parameters

(* View: lns
    A top-level <Erlang.config> *)
let lns = Erlang.config rabbit

(* Variable: filter *)
let filter = incl "/etc/rabbitmq/rabbitmq.config"

let xfm = transform lns filter


Shellvars: add BSD's /etc/rc.conf

Shellvars: add BSD's /etc/rc.conf

Fixes ticket #255

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

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

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let eol = del /[ \t]+|[ \t]*[;\n]/ "\n"
  let semicol_eol = del /[ \t]*[;\n]/ "\n"

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

  let comment = Util.comment
  let comment_eol = Util.comment_eol
  let comment_or_eol = comment_eol | semicol_eol

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

  let char  = /[^;#() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  (* For some reason, `` conflicts with comment_or_eol *)
  let bquot = /`[^#`\n]*`/
  let dollar_assign = /\$\([^#`\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\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 | dollar_assign | empty_array)

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

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

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

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

  let shell_builtin_cmds = "ulimit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . Util.del_ws_spc
      . [ label "args" . sto_to_semicol ]
      . comment_or_eol ]

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

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

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

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

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

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

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

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

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

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

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry+
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store char+
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . case_entry+
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | empty | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

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

  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 "snmpd" .
      sc_incl "snmpd.options" .
      sc_incl "snmptrapd" .
      sc_incl "snmptrapd.options" .
      sc_incl "spamassassin" .
      sc_incl "suseconfig" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_sysconfig_suse =
      sc_incl "abuild" .
      sc_incl "add-on-creator" .
      sc_incl "amavis" .
      sc_incl "amazon" .
      sc_incl "apache2" .
      sc_incl "argus" .
      sc_incl "arpwatch" .
      sc_incl "auditd" .
      sc_incl "autoinstall" .
      sc_incl "autoupdate" .
      sc_incl "backup" .
      sc_incl "bigsister" .
      sc_incl "bluetooth" .
      sc_incl "boot" .
      sc_incl "bootloader" .
      sc_incl "bootsplash" .
      sc_incl "cgred" .
      sc_incl "console" .
      sc_incl "cron" .
      sc_incl "ctdb" .
      sc_incl "cups" .
      sc_incl "ddclient" .
      sc_incl "dhcpd" .
      sc_incl "dhcrelay" .
      sc_incl "displaymanager" .
      sc_incl "dmraid" .
      sc_incl "dracd" .
      sc_incl "esound" .
      sc_incl "fam" .
      sc_incl "festival" .
      sc_incl "fetchmail" .
      sc_incl "fonts-config" .
      sc_incl "git-daemon" .
      sc_incl "gpsd" .
      sc_incl "hardware" .
      sc_incl "hardware/*" .
      sc_incl "icecream" .
      sc_incl "ide" .
      sc_incl "infiniband" .
      sc_incl "inputattach" .
      sc_incl "ipmi" .
      sc_incl "ipvsadm" .
      sc_incl "ispell" .
      sc_incl "joystick" .
      sc_incl "kernel-tunables" .
      sc_incl "language" .
      sc_incl "ldap" .
      sc_incl "lighttpd" .
      sc_incl "lirc" .
      sc_incl "locate" .
      sc_incl "lvm" .
      sc_incl "mail" .
      sc_incl "mailman" .
      sc_incl "mdadm" .
      sc_incl "media-changer" .
      sc_incl "memcached" .
      sc_incl "mouse" .
      sc_incl "mpi-selector" .
      sc_incl "mysql" .
      sc_incl "nagios" .
      sc_incl "named" .
      sc_incl "ncpfs" .
      sc_incl "net-snmp" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_incl "news" .
      sc_incl "ntp" .
      sc_incl "obs-server" .
      sc_incl "obs-worker" .
      sc_incl "openldap" .
      sc_incl "opensm" .
      sc_incl "osa-dispatcher" .
      sc_incl "pm-profiler" .
      sc_incl "portmap" .
      sc_incl "postfix" .
      sc_incl "postgresql" .
      sc_incl "product-creator" .
      sc_incl "proxy" .
      sc_incl "ptpd" .
      sc_incl "radvd" .
      sc_incl "readonlyroot" .
      sc_incl "rpcbind" .
      sc_incl "sapconf" .
      sc_incl "scpm" .
      sc_incl "seccheck" .
      sc_incl "security" .
      sc_incl "services" .
      sc_incl "shutdown" .
      sc_incl "smt-client" .
      sc_incl "sound" .
      sc_incl "spamd" .
      sc_incl "squid" .
      sc_incl "ssh" .
      sc_incl "storage" .
      sc_incl "SuSEfirewall2" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_incl "susehelp" .
      sc_incl "suse_register" .
      sc_incl "sysctl" .
      sc_incl "syslog" .
      sc_incl "texlive" .
      sc_incl "ulimit" .
      sc_incl "websphere-as_ce-2.1" .
      sc_incl "windowmanager" .
      sc_incl "wondershaper" .
      sc_incl "words" .
      sc_incl "yast2" .
      sc_incl "ypbind" .
      sc_incl "ypserv"

  let filter_sysconfig_rhn =
      sc_incl "rhn/allowed-actions/*" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/clientCaps.d/*" .
      sc_incl "rhn/osad-auth.conf" .
      sc_incl "rhn/osad.conf" .
      sc_incl "rhn/rhncfg-client.conf" .
      sc_incl "rhn/rhncfg-manager.conf" .
      sc_incl "rhn/rhnpushrc" .
      sc_incl "rhn/rhnsd" .
      sc_incl "rhn/up2date" .
      sc_incl "rhn/virt" .
      sc_incl "rhn/virt/auto"

  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"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/ucf.conf"
                     . incl "/etc/updatedb.conf"

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

  let xfm = transform lns filter

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

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

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

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let eol = del /[ \t]+|[ \t]*[;\n]/ "\n"
  let semicol_eol = del /[ \t]*[;\n]/ "\n"

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

  let comment = Util.comment
  let comment_eol = Util.comment_eol
  let comment_or_eol = comment_eol | semicol_eol

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

  let char  = /[^;#() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  (* For some reason, `` conflicts with comment_or_eol *)
  let bquot = /`[^#`\n]*`/
  let dollar_assign = /\$\([^#`\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\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 | dollar_assign | empty_array)

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

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

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

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

  let shell_builtin_cmds = "ulimit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . Util.del_ws_spc
      . [ label "args" . sto_to_semicol ]
      . comment_or_eol ]

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

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

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

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

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

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

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

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

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

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

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry+
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store char+
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . case_entry+
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | empty | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

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

  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 "snmpd" .
      sc_incl "snmpd.options" .
      sc_incl "snmptrapd" .
      sc_incl "snmptrapd.options" .
      sc_incl "spamassassin" .
      sc_incl "suseconfig" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_sysconfig_suse =
      sc_incl "abuild" .
      sc_incl "add-on-creator" .
      sc_incl "amavis" .
      sc_incl "amazon" .
      sc_incl "apache2" .
      sc_incl "argus" .
      sc_incl "arpwatch" .
      sc_incl "auditd" .
      sc_incl "autoinstall" .
      sc_incl "autoupdate" .
      sc_incl "backup" .
      sc_incl "bigsister" .
      sc_incl "bluetooth" .
      sc_incl "boot" .
      sc_incl "bootloader" .
      sc_incl "bootsplash" .
      sc_incl "cgred" .
      sc_incl "console" .
      sc_incl "cron" .
      sc_incl "ctdb" .
      sc_incl "cups" .
      sc_incl "ddclient" .
      sc_incl "dhcpd" .
      sc_incl "dhcrelay" .
      sc_incl "displaymanager" .
      sc_incl "dmraid" .
      sc_incl "dracd" .
      sc_incl "esound" .
      sc_incl "fam" .
      sc_incl "festival" .
      sc_incl "fetchmail" .
      sc_incl "fonts-config" .
      sc_incl "git-daemon" .
      sc_incl "gpsd" .
      sc_incl "hardware" .
      sc_incl "hardware/*" .
      sc_incl "icecream" .
      sc_incl "ide" .
      sc_incl "infiniband" .
      sc_incl "inputattach" .
      sc_incl "ipmi" .
      sc_incl "ipvsadm" .
      sc_incl "ispell" .
      sc_incl "joystick" .
      sc_incl "kernel-tunables" .
      sc_incl "language" .
      sc_incl "ldap" .
      sc_incl "lighttpd" .
      sc_incl "lirc" .
      sc_incl "locate" .
      sc_incl "lvm" .
      sc_incl "mail" .
      sc_incl "mailman" .
      sc_incl "mdadm" .
      sc_incl "media-changer" .
      sc_incl "memcached" .
      sc_incl "mouse" .
      sc_incl "mpi-selector" .
      sc_incl "mysql" .
      sc_incl "nagios" .
      sc_incl "named" .
      sc_incl "ncpfs" .
      sc_incl "net-snmp" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_incl "news" .
      sc_incl "ntp" .
      sc_incl "obs-server" .
      sc_incl "obs-worker" .
      sc_incl "openldap" .
      sc_incl "opensm" .
      sc_incl "osa-dispatcher" .
      sc_incl "pm-profiler" .
      sc_incl "portmap" .
      sc_incl "postfix" .
      sc_incl "postgresql" .
      sc_incl "product-creator" .
      sc_incl "proxy" .
      sc_incl "ptpd" .
      sc_incl "radvd" .
      sc_incl "readonlyroot" .
      sc_incl "rpcbind" .
      sc_incl "sapconf" .
      sc_incl "scpm" .
      sc_incl "seccheck" .
      sc_incl "security" .
      sc_incl "services" .
      sc_incl "shutdown" .
      sc_incl "smt-client" .
      sc_incl "sound" .
      sc_incl "spamd" .
      sc_incl "squid" .
      sc_incl "ssh" .
      sc_incl "storage" .
      sc_incl "SuSEfirewall2" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_incl "susehelp" .
      sc_incl "suse_register" .
      sc_incl "sysctl" .
      sc_incl "syslog" .
      sc_incl "texlive" .
      sc_incl "ulimit" .
      sc_incl "websphere-as_ce-2.1" .
      sc_incl "windowmanager" .
      sc_incl "wondershaper" .
      sc_incl "words" .
      sc_incl "yast2" .
      sc_incl "ypbind" .
      sc_incl "ypserv"

  let filter_sysconfig_rhn =
      sc_incl "rhn/allowed-actions/*" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/clientCaps.d/*" .
      sc_incl "rhn/osad-auth.conf" .
      sc_incl "rhn/osad.conf" .
      sc_incl "rhn/rhncfg-client.conf" .
      sc_incl "rhn/rhncfg-manager.conf" .
      sc_incl "rhn/rhnpushrc" .
      sc_incl "rhn/rhnsd" .
      sc_incl "rhn/up2date" .
      sc_incl "rhn/virt" .
      sc_incl "rhn/virt/auto"

  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"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/ucf.conf"
                     . incl "/etc/updatedb.conf"

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

  let xfm = transform lns filter

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


Shellvars: include /etc/{default,sysconfig}/* and list exceptions instead

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

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

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let eol = del /[ \t]+|[ \t]*[;\n]/ "\n"
  let semicol_eol = del /[ \t]*[;\n]/ "\n"

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

  let comment = Util.comment
  let comment_eol = Util.comment_eol
  let comment_or_eol = comment_eol | semicol_eol

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

  let char  = /[^;#() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  (* For some reason, `` conflicts with comment_or_eol *)
  let bquot = /`[^#`\n]*`/
  let dollar_assign = /\$\([^#`\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\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 | dollar_assign | empty_array)

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

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

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

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

  let shell_builtin_cmds = "ulimit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . Util.del_ws_spc
      . [ label "args" . sto_to_semicol ]
      . comment_or_eol ]

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

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

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

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

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

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

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

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

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

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

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry+
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store char+
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . case_entry+
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | empty | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

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

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

  let filter_sysconfig =
      sc_incl "*" .
      sc_excl "kernel" .
      sc_excl "ip*tables" .
      sc_excl "sysstat.ioconf" .
      sc_excl "system-config-firewall" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_incl "rhn/allowed-actions/*" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_excl "SuSEfirewall2.d/services/TEMPLATE"

  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"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/ucf.conf"

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

  let xfm = transform lns filter

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

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

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

About: Lens Usage
   To be documented
*)

module Shellvars =
  autoload xfm

  let eol = del /[ \t]+|[ \t]*[;\n]/ "\n"
  let semicol_eol = del /[ \t]*[;\n]/ "\n"

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

  let comment = Util.comment
  let comment_eol = Util.comment_eol
  let comment_or_eol = comment_eol | semicol_eol

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

  let char  = /[^;#() '"\t\n]|\\\\"/
  let dquot = /"([^"\\\n]|\\\\.)*"/                    (* " Emacs, relax *)
  let squot = /'[^'\n]*'/
  (* For some reason, `` conflicts with comment_or_eol *)
  let bquot = /`[^#`\n]*`/
  let dollar_assign = /\$\([^#`\n]*\)/

  let sto_to_semicol = store /[^#; \t\n][^#;\n]+[^#; \t\n]|[^#; \t\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 | dollar_assign | empty_array)

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

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

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

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

  let shell_builtin_cmds = "ulimit"

  let builtin =
    [ Util.indent . label "@builtin"
      . store shell_builtin_cmds
      . Util.del_ws_spc
      . [ label "args" . sto_to_semicol ]
      . comment_or_eol ]

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

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

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

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

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

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

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

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

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

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

  let case (entry:lens) =
    let case_entry = [ label "@case_entry"
                       . Util.indent . store /[^ \t\n\)]+/
                       . Util.del_str ")" . eol
                       . entry+
                       . Util.indent . Util.del_str ";;" . eol ] in
      [ keyword_label "case" "@case" . Sep.space
        . store char+
        . del /[ \t\n]+/ " " . Util.del_str "in" . eol
        . case_entry+
        . keyword "esac" . comment_or_eol ]

  let function (entry:lens) =
    [ Util.indent . label "@function"
      . del /(function[ \t]+)?/ ""
      . store Rx.word . del /[ \t]*\(\)/ "()"
      . eol . Util.del_str "{" . eol
      . entry+
      . Util.indent . Util.del_str "}" . eol ]

  let rec rec_entry =
    let entry = comment | empty | source | kv
              | unset | bare_export | builtin | return | rec_entry in
        cond_if entry
      | loop_for entry
      | loop_select entry
      | loop_while entry
      | loop_until entry
      | case entry
      | function entry

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

  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 "snmpd" .
      sc_incl "snmpd.options" .
      sc_incl "snmptrapd" .
      sc_incl "snmptrapd.options" .
      sc_incl "spamassassin" .
      sc_incl "suseconfig" .
      sc_incl "sysstat" .
      sc_incl "system-config-users" .
      sc_incl "vncservers" .
      sc_incl "wpa_supplicant" .
      sc_incl "xend" .
      sc_incl "xendomains"

  let filter_sysconfig_suse =
      sc_incl "abuild" .
      sc_incl "add-on-creator" .
      sc_incl "amavis" .
      sc_incl "amazon" .
      sc_incl "apache2" .
      sc_incl "argus" .
      sc_incl "arpwatch" .
      sc_incl "auditd" .
      sc_incl "autoinstall" .
      sc_incl "autoupdate" .
      sc_incl "backup" .
      sc_incl "bigsister" .
      sc_incl "bluetooth" .
      sc_incl "boot" .
      sc_incl "bootloader" .
      sc_incl "bootsplash" .
      sc_incl "cgred" .
      sc_incl "console" .
      sc_incl "cron" .
      sc_incl "ctdb" .
      sc_incl "cups" .
      sc_incl "ddclient" .
      sc_incl "dhcpd" .
      sc_incl "dhcrelay" .
      sc_incl "displaymanager" .
      sc_incl "dmraid" .
      sc_incl "dracd" .
      sc_incl "esound" .
      sc_incl "fam" .
      sc_incl "festival" .
      sc_incl "fetchmail" .
      sc_incl "fonts-config" .
      sc_incl "git-daemon" .
      sc_incl "gpsd" .
      sc_incl "hardware" .
      sc_incl "hardware/*" .
      sc_incl "icecream" .
      sc_incl "ide" .
      sc_incl "infiniband" .
      sc_incl "inputattach" .
      sc_incl "ipmi" .
      sc_incl "ipvsadm" .
      sc_incl "ispell" .
      sc_incl "joystick" .
      sc_incl "kernel-tunables" .
      sc_incl "language" .
      sc_incl "ldap" .
      sc_incl "lighttpd" .
      sc_incl "lirc" .
      sc_incl "locate" .
      sc_incl "lvm" .
      sc_incl "mail" .
      sc_incl "mailman" .
      sc_incl "mdadm" .
      sc_incl "media-changer" .
      sc_incl "memcached" .
      sc_incl "mouse" .
      sc_incl "mpi-selector" .
      sc_incl "mysql" .
      sc_incl "nagios" .
      sc_incl "named" .
      sc_incl "ncpfs" .
      sc_incl "net-snmp" .
      sc_incl "network/config" .
      sc_incl "network/dhcp" .
      sc_incl "network/dhcp6r" .
      sc_incl "network/dhcp6s" .
      sc_incl "network/ifcfg-*" .
      sc_incl "network/if-down.d/*" .
      sc_incl "network/ifroute-*" .
      sc_incl "network/if-up.d/*" .
      sc_incl "network/providers/*" .
      sc_incl "news" .
      sc_incl "ntp" .
      sc_incl "obs-server" .
      sc_incl "obs-worker" .
      sc_incl "openldap" .
      sc_incl "opensm" .
      sc_incl "osa-dispatcher" .
      sc_incl "pm-profiler" .
      sc_incl "portmap" .
      sc_incl "postfix" .
      sc_incl "postgresql" .
      sc_incl "product-creator" .
      sc_incl "proxy" .
      sc_incl "ptpd" .
      sc_incl "radvd" .
      sc_incl "readonlyroot" .
      sc_incl "rpcbind" .
      sc_incl "sapconf" .
      sc_incl "scpm" .
      sc_incl "seccheck" .
      sc_incl "security" .
      sc_incl "services" .
      sc_incl "shutdown" .
      sc_incl "smt-client" .
      sc_incl "sound" .
      sc_incl "spamd" .
      sc_incl "squid" .
      sc_incl "ssh" .
      sc_incl "storage" .
      sc_incl "SuSEfirewall2" .
      sc_incl "SuSEfirewall2.d/cobbler" .
      sc_incl "SuSEfirewall2.d/services/*" .
      sc_incl "susehelp" .
      sc_incl "suse_register" .
      sc_incl "sysctl" .
      sc_incl "syslog" .
      sc_incl "texlive" .
      sc_incl "ulimit" .
      sc_incl "websphere-as_ce-2.1" .
      sc_incl "windowmanager" .
      sc_incl "wondershaper" .
      sc_incl "words" .
      sc_incl "yast2" .
      sc_incl "ypbind" .
      sc_incl "ypserv"

  let filter_sysconfig_rhn =
      sc_incl "rhn/allowed-actions/*" .
      sc_incl "rhn/allowed-actions/script/*" .
      sc_incl "rhn/rhnsd"

  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"
                     . incl "/etc/blkid.conf"
                     . incl "/etc/adduser.conf"
                     . incl "/etc/cowpoke.conf"
                     . incl "/etc/cvs-cron.conf"
                     . incl "/etc/cvs-pserver.conf"
                     . incl "/etc/devscripts.conf"
                     . incl "/etc/lintianrc"
                     . incl "/etc/lsb-release"
                     . incl "/etc/popularity-contest.conf"
                     . incl "/etc/rc.conf"
                     . incl "/etc/ucf.conf"

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

  let xfm = transform lns filter

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


Interfaces: add /etc/network/interfaces.d/* as another commonly used location

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

 Reference: man interfaces

*)

module Interfaces =
   autoload xfm

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

let eol        = Util.eol

(* Define separators *)

(* a line can be extended across multiple lines by making the last  *)
(*  character a backslash *)
let sep_spc    =  del /([ \t]+|[ \t]*\\\\\n[ \t]*)/ " "

(* Define fields *)
let sto_to_eol = store /([^\\ \t\n].*[^\\ \t\n]|[^\\ \t\n])/ . eol
let sto_to_spc = store /[^\\ \t\n]+/

(* Define comments and empty lines *)

(* note that the comment definition from Util does not support *)
(* splitting lines with a backlash                             *)
let comment    = Util.comment

let empty      = Util.empty

(* Define tree stanza_ids *)
let stanza_id    (t:string) = key t . sep_spc . sto_to_spc
let stanza_param (l:string) = [ sep_spc . label l . sto_to_spc ]

(* Define reseverved words *)
let stanza_word = /(source|iface|auto|allow-[a-z-]+|mapping)/

(* Define additional lines for multi-line stanzas *)
let stanza_option = [  del /[ \t]*/ "   "
                     . key  ( /[a-z_-]+/ - stanza_word )
                     . sep_spc
                     . sto_to_eol ]

(************************************************************************
 *                              AUTO
 *************************************************************************)

let array (r:regexp) (t:string) =  del r t . label t . counter t
   . [ sep_spc . seq t . sto_to_spc ]+
let auto = [ array /(allow-)?auto/ "auto" . eol ]

(************************************************************************
 *                              GENERIC ALLOW
 *************************************************************************)

let allow = [ key ( /allow-[a-z-]+/ - "allow-auto" )
             . counter "allow_seq"
             . [ sep_spc . seq "allow_seq" . sto_to_spc ]+
             . eol ]

(************************************************************************
 *                              MAPPING
 *************************************************************************)

let mapping = [ stanza_id "mapping"
               . eol
               . (stanza_option|comment|empty)+ ]

(************************************************************************
 *                              IFACE
 *************************************************************************)

let iface   = [ Util.indent
              . stanza_id    "iface"
              . stanza_param "family"
              . stanza_param "method"
              . eol
              . (stanza_option|comment|empty)* ]

(************************************************************************
 *                              SOURCE
 *************************************************************************)

let source = [ key "source" . sep_spc . sto_to_eol ]

(************************************************************************
 *                              STANZAS
 *************************************************************************)

(* The auto and hotplug stanzas always consist of one line only, while
   iface and mapping can spand along more lines. Comment nodes are
   inserted in the tree as direct children of the root node only when they
   come after an auto or hotplug stanza, otherwise they are considered part
   of a iface or mapping block *)

let stanza_single = (auto|allow|source) . (comment|empty)*
let stanza_multi  = iface|mapping

(************************************************************************
 *                              LENS & FILTER
 *************************************************************************)

   let lns = (comment|empty)* . (stanza_multi | stanza_single)*

   let filter = (incl "/etc/network/interfaces")
                . (incl "/etc/network/interfaces.d/*")
                . Util.stdexcl

   let xfm = transform lns filter

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

 Reference: man interfaces

*)

module Interfaces =
   autoload xfm

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

let eol        = Util.eol

(* Define separators *)

(* a line can be extended across multiple lines by making the last  *)
(*  character a backslash *)
let sep_spc    =  del /([ \t]+|[ \t]*\\\\\n[ \t]*)/ " "

(* Define fields *)
let sto_to_eol = store /([^\\ \t\n].*[^\\ \t\n]|[^\\ \t\n])/ . eol
let sto_to_spc = store /[^\\ \t\n]+/

(* Define comments and empty lines *)

(* note that the comment definition from Util does not support *)
(* splitting lines with a backlash                             *)
let comment    = Util.comment

let empty      = Util.empty

(* Define tree stanza_ids *)
let stanza_id    (t:string) = key t . sep_spc . sto_to_spc
let stanza_param (l:string) = [ sep_spc . label l . sto_to_spc ]

(* Define reseverved words *)
let stanza_word = /(source|iface|auto|allow-[a-z-]+|mapping)/

(* Define additional lines for multi-line stanzas *)
let stanza_option = [  del /[ \t]*/ "   "
                     . key  ( /[a-z_-]+/ - stanza_word )
                     . sep_spc
                     . sto_to_eol ]

(************************************************************************
 *                              AUTO
 *************************************************************************)

let array (r:regexp) (t:string) =  del r t . label t . counter t
   . [ sep_spc . seq t . sto_to_spc ]+
let auto = [ array /(allow-)?auto/ "auto" . eol ]

(************************************************************************
 *                              GENERIC ALLOW
 *************************************************************************)

let allow = [ key ( /allow-[a-z-]+/ - "allow-auto" )
             . counter "allow_seq"
             . [ sep_spc . seq "allow_seq" . sto_to_spc ]+
             . eol ]

(************************************************************************
 *                              MAPPING
 *************************************************************************)

let mapping = [ stanza_id "mapping"
               . eol
               . (stanza_option|comment|empty)+ ]

(************************************************************************
 *                              IFACE
 *************************************************************************)

let iface   = [ Util.indent
              . stanza_id    "iface"
              . stanza_param "family"
              . stanza_param "method"
              . eol
              . (stanza_option|comment|empty)* ]

(************************************************************************
 *                              SOURCE
 *************************************************************************)

let source = [ key "source" . sep_spc . sto_to_eol ]

(************************************************************************
 *                              STANZAS
 *************************************************************************)

(* The auto and hotplug stanzas always consist of one line only, while
   iface and mapping can spand along more lines. Comment nodes are
   inserted in the tree as direct children of the root node only when they
   come after an auto or hotplug stanza, otherwise they are considered part
   of a iface or mapping block *)

let stanza_single = (auto|allow|source) . (comment|empty)*
let stanza_multi  = iface|mapping

(************************************************************************
 *                              LENS & FILTER
 *************************************************************************)

   let lns = (comment|empty)* . (stanza_multi | stanza_single)*

   let filter = incl "/etc/network/interfaces"

   let xfm = transform lns filter


Test_Nginx: no functional change, reformatted

(*
Module: Test_Nginx
  Provides unit tests and examples for the <Nginx> lens.
*)
module Test_nginx =

let lns = Nginx.lns

let conf ="user nginx nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;

events {
        worker_connections 1024;
        use epoll;
}

# comment1
# comment2

http {
	# comment3
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        log_format main
                '$remote_addr - $remote_user [$time_local] '
                '\"$request\" $status $bytes_sent '
                '\"$http_referer\" \"$http_user_agent\" '
                '\"$gzip_ratio\"';
        client_header_timeout 10m;
        client_body_timeout 10m;
        send_timeout 10m;
        connection_pool_size 256;
        client_header_buffer_size 2k;
        large_client_header_buffers 4 8k;
        request_pool_size 4k;
        gzip on;
	gzip_min_length 1000;
        gzip_buffers 4 8k;
        gzip_types text/plain application/json;
        output_buffers 1 32k;
        postpone_output 1460;
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 75 20;
        ignore_invalid_headers on;
        index index.html index.php;
        include vhosts/*.conf;
}
"

test lns get conf =
   { "user"  = "nginx nginx" }
   { "worker_processes"      = "1" }
   { "error_log" = "/var/log/nginx/error_log info" }
   {}
   { "events"
      { "worker_connections"  = "1024" }
      { "use"      = "epoll" } }
   {}
   { "#comment" = "comment1" }
   { "#comment" = "comment2" }
   {}
   { "http"
   	  { "#comment" = "comment3" }
      { "include"  = "/etc/nginx/mime.types" }
      { "default_type"  = "application/octet-stream" }
      { "log_format"      = "main
                '$remote_addr - $remote_user [$time_local] '
                '\"$request\" $status $bytes_sent '
                '\"$http_referer\" \"$http_user_agent\" '
                '\"$gzip_ratio\"'" }
      { "client_header_timeout"  = "10m" }
      { "client_body_timeout"  = "10m" }
      { "send_timeout"      = "10m" }
      { "connection_pool_size"      = "256" }
      { "client_header_buffer_size"      = "2k" }
      { "large_client_header_buffers"      = "4 8k" }
      { "request_pool_size"      = "4k" }
      { "gzip"      = "on" }
      { "gzip_min_length"      = "1000" }
      { "gzip_buffers"      = "4 8k" }
      { "gzip_types"      = "text/plain application/json" }
      { "output_buffers"      = "1 32k" }
      { "postpone_output"      = "1460" }
      { "sendfile"      = "on" }
      { "tcp_nopush"      = "on" }
      { "tcp_nodelay"      = "on" }
      { "keepalive_timeout"      = "75 20" }
      { "ignore_invalid_headers"      = "on" }
      { "index"      = "index.html index.php" }
      { "include"      = "vhosts/*.conf" } }

(*
Module: Test_Nginx
  Provides unit tests and examples for the <Nginx> lens.
*)
module Test_nginx =

    let conf ="user nginx nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;

events {
        worker_connections 1024;
        use epoll;
}

# comment1
# comment2

http {
	# comment3
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        log_format main
                '$remote_addr - $remote_user [$time_local] '
                '\"$request\" $status $bytes_sent '
                '\"$http_referer\" \"$http_user_agent\" '
                '\"$gzip_ratio\"';
        client_header_timeout 10m;
        client_body_timeout 10m;
        send_timeout 10m;
        connection_pool_size 256;
        client_header_buffer_size 2k;
        large_client_header_buffers 4 8k;
        request_pool_size 4k;
        gzip on;
	gzip_min_length 1000;
        gzip_buffers 4 8k;
        gzip_types text/plain application/json;
        output_buffers 1 32k;
        postpone_output 1460;
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 75 20;
        ignore_invalid_headers on;
        index index.html index.php;
        include vhosts/*.conf;
}
"

    test Nginx.lns get conf =
       { "user"  = "nginx nginx" }
       { "worker_processes"      = "1" }
       { "error_log" = "/var/log/nginx/error_log info" }
       {}
       { "events"
          { "worker_connections"  = "1024" }
          { "use"      = "epoll" } }
       {}
       { "#comment" = "comment1" }
       { "#comment" = "comment2" }
       {}
       { "http"
       	  { "#comment" = "comment3" }
          { "include"  = "/etc/nginx/mime.types" }
          { "default_type"  = "application/octet-stream" }
          { "log_format"      = "main
                '$remote_addr - $remote_user [$time_local] '
                '\"$request\" $status $bytes_sent '
                '\"$http_referer\" \"$http_user_agent\" '
                '\"$gzip_ratio\"'" }
          { "client_header_timeout"  = "10m" }
          { "client_body_timeout"  = "10m" }
          { "send_timeout"      = "10m" }
          { "connection_pool_size"      = "256" }
          { "client_header_buffer_size"      = "2k" }
          { "large_client_header_buffers"      = "4 8k" }
          { "request_pool_size"      = "4k" }
          { "gzip"      = "on" }
          { "gzip_min_length"      = "1000" }
          { "gzip_buffers"      = "4 8k" }
          { "gzip_types"      = "text/plain application/json" }
          { "output_buffers"      = "1 32k" }
          { "postpone_output"      = "1460" }
          { "sendfile"      = "on" }
          { "tcp_nopush"      = "on" }
          { "tcp_nodelay"      = "on" }
          { "keepalive_timeout"      = "75 20" }
          { "ignore_invalid_headers"      = "on" }
          { "index"      = "index.html index.php" }
          { "include"      = "vhosts/*.conf" } }


Support debug flag in keepalived.aug

Support debug flag in keepalived.aug

(*
Module: Keepalived
  Parses /etc/keepalived/keepalived.conf

Author: Raphael Pinson <raphink@gmail.com>

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

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/keepalived/keepalived.conf. See <filter>.
*)

module Keepalived =
  autoload xfm

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

(* Group: Comments and empty lines *)

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

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

(* View: opt_eol *)
let opt_eol = del /[ \t]*\n?/ " "

(* View: sep_spc *)
let sep_spc = Sep.space

(* View: sep_opt_spc *)
let sep_opt_spc = Sep.opt_space

(* View: sep_dquot *)
let sep_dquot = Util.del_str "\""

(* View: lbracket *)
let lbracket = Util.del_str "{"

(* View: rbracket *)
let rbracket = Util.del_str "}"

(* View: comment
Map comments in "#comment" nodes *)
let comment = Util.comment_generic /[ \t]*[#!][ \t]*/ "# "

(* View: comment_eol
Map comments at eol *)
let comment_eol = Util.comment_generic /[ \t]*[#!][ \t]*/ " # "

(* View: comment_or_eol
A <comment_eol> or <eol> *)
let comment_or_eol = comment_eol | (del /[ \t]*[#!]?\n/ "\n")

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

(* View: sto_email_addr *)
let sto_email_addr = store Rx.email_addr

(* Variable: word *)
let word = Rx.word

(* Variable: word_slash *)
let word_slash = word | "/"

(* View: sto_word *)
let sto_word = store word

(* View: sto_num *)
let sto_num = store Rx.relinteger

(* View: sto_to_eol *)
let sto_to_eol = store /[^#! \t\n][^#!\n]*[^#! \t\n]|[^#! \t\n]/

(* View: field *)
let field (kw:string) (sto:lens) = indent . Build.key_value_line_comment kw sep_spc sto comment_eol

(* View: flag
A single word *)
let flag (kw:regexp) = [ indent . key kw . comment_or_eol ]

(* View: lens_block
A generic block with a title lens *)
let lens_block (title:lens) (sto:lens) = [ indent . title . opt_eol . lbracket
                                         . (sto | empty | comment)+
                                         . indent . rbracket . eol ]

(* View: block
A simple block with just a block title *)
let block (kw:string) (sto:lens) = lens_block (key kw) sto

(* View: named_block
A block with a block title and name *)
let named_block (kw:string) (sto:lens) = lens_block (key kw . sep_spc . sto_word) sto

(* View: named_block_arg_title
A title lens for named_block_arg *)
let named_block_arg_title (kw:string) (name:string) (arg:string) =
                            key kw . sep_spc
                          . [ label name . sto_word ]
                          . sep_spc
                          . [ label arg . sto_word ]

(* View: named_block_arg
A block with a block title, a name and an argument *)
let named_block_arg (kw:string) (name:string) (arg:string) (sto:lens) =
                           lens_block (named_block_arg_title kw name arg) sto

(************************************************************************
 * Group:                 GLOBAL CONFIGURATION
 *************************************************************************)

(* View: email
A simple email address entry *)
let email = [ indent . label "email" . sto_email_addr . comment_or_eol ]

(* View: global_defs_field
Possible fields in the global_defs block *)
let global_defs_field = block "notification_email" email
                      | field "notification_email_from" sto_email_addr
                      | field "smtp_server" sto_word
                      | field "smtp_connect_timeout" sto_num
                      | field "lvs_id" sto_word
                      | field "router_id" sto_word

(* View: global_defs
A global_defs block *)
let global_defs = block "global_defs" global_defs_field

(* View: prefixlen
A prefix for IP addresses *)
let prefixlen = [ label "prefixlen" . Util.del_str "/" . sto_num ]

(* View: ipaddr
An IP address or range with an optional mask *)
let ipaddr = label "ipaddr" . store /[0-9.-]+/ . prefixlen?

(* View: ipdev
A device for IP addresses *)
let ipdev = [ key "dev" . sep_spc . sto_word ]

(* View: static_ipaddress_field
The whole string is fed to ip addr add.
You can truncate the string anywhere you like and let ip addr add use defaults for the rest of the string.
To be refined with fields according to `ip addr help`.
*)
let static_ipaddress_field = [ indent . ipaddr
                             . (sep_spc . ipdev)?
                             . comment_or_eol ]

(* View: static_routes_field
src $SRC_IP to $DST_IP dev $SRC_DEVICE
*)
let static_routes_field = [ indent . label "route"
                          . [ key "src" . sto_word ] . sep_spc
                          . [ key "to"  . sto_word ] . sep_spc
                          . [ key "dev" . sto_word ] . comment_or_eol ]

(* View: static_routes *)
let static_routes = block "static_ipaddress" static_ipaddress_field
                  | block "static_routes" static_routes_field

(* View: global_conf
A global configuration entry *)
let global_conf = global_defs | static_routes

(************************************************************************
 * Group:                 VRRP CONFIGURATION
 *************************************************************************)

(*View: vrrp_sync_group_field *)
let vrrp_sync_group_field = block "group" [ indent . key word . comment_or_eol ]

(* View: vrrp_sync_group *)
let vrrp_sync_group = named_block "vrrp_sync_group" vrrp_sync_group_field

(* View: vrrp_instance_field *)
let vrrp_instance_field = field "state" sto_word
                        | field "interface" sto_word
                        | field "lvs_sync_daemon_interface" sto_word
                        | field "virtual_router_id" sto_num
                        | field "priority" sto_num
                        | field "advert_int" sto_num
                        | field "garp_master_delay" sto_num
                        | field "notify_master" sto_to_eol
                        | field "notify_backup" sto_to_eol
                        | field "notify_fault" sto_to_eol
                        | flag "smtp_alert"
                        | flag "nopreempt"
                        | flag "ha_suspend"
                        | flag "debug"
                        | block "authentication" (
                                field "auth_type" sto_word
                              | field "auth_pass" sto_word
                              )
                        | block "virtual_ipaddress" static_ipaddress_field
                        | block "track_interface" ( flag word )
                        | block "track_script" ( flag word )

(* View: vrrp_instance *)
let vrrp_instance = named_block "vrrp_instance" vrrp_instance_field

(* View: vrrp_script_field *)
let vrrp_script_field = field "script" sto_to_eol
                      | field "interval" sto_num
                      | field "weight" sto_num

(* View: vrrp_script *)
let vrrp_script = named_block "vrrp_script" vrrp_script_field

(* View: vrrpd_conf
contains subblocks of VRRP synchronization group(s) and VRRP instance(s) *)
let vrrpd_conf = vrrp_sync_group | vrrp_instance | vrrp_script

(************************************************************************
 * Group:                 LVS CONFIGURATION
 *************************************************************************)

(* View: tcp_check_field *)
let tcp_check_field = field "connect_timeout" sto_num
                    | field "connect_port" sto_num

(* View: real_server_field *)
let real_server_field = field "weight" sto_num
                      | block "TCP_CHECK" tcp_check_field

(* View: virtual_server_field *)
let virtual_server_field = field "delay_loop" sto_num
                         | field "lb_algo" sto_word
                         | field "lb_kind" sto_word
                         | field "nat_mask" sto_word
                         | field "protocol" sto_word
                         | named_block_arg "real_server" "ip" "port" real_server_field

(* View: virtual_server *)
let virtual_server = named_block_arg "virtual_server" "ip" "port" virtual_server_field

(* View: virtual_server_group_field *)
let virtual_server_group_field = [ indent . label "vip"
                               . [ ipaddr ]
			       . sep_spc
			       . [ label "port" . sto_num ]
			       . comment_or_eol ]

(* View: virtual_server_group *)
let virtual_server_group = named_block "virtual_server_group" virtual_server_group_field

(* View: lvs_conf
contains subblocks of Virtual server group(s) and Virtual server(s) *)
let lvs_conf = virtual_server | virtual_server_group

(* View: lns
     The keepalived lens
*)
let lns = ( empty | comment | global_conf | vrrpd_conf | lvs_conf )*

(* Variable: filter *)
let filter = incl "/etc/keepalived/keepalived.conf"
    . Util.stdexcl

let xfm = transform lns filter

(*
Module: Keepalived
  Parses /etc/keepalived/keepalived.conf

Author: Raphael Pinson <raphink@gmail.com>

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

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/keepalived/keepalived.conf. See <filter>.
*)

module Keepalived =
  autoload xfm

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

(* Group: Comments and empty lines *)

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

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

(* View: opt_eol *)
let opt_eol = del /[ \t]*\n?/ " "

(* View: sep_spc *)
let sep_spc = Sep.space

(* View: sep_opt_spc *)
let sep_opt_spc = Sep.opt_space

(* View: sep_dquot *)
let sep_dquot = Util.del_str "\""

(* View: lbracket *)
let lbracket = Util.del_str "{"

(* View: rbracket *)
let rbracket = Util.del_str "}"

(* View: comment
Map comments in "#comment" nodes *)
let comment = Util.comment_generic /[ \t]*[#!][ \t]*/ "# "

(* View: comment_eol
Map comments at eol *)
let comment_eol = Util.comment_generic /[ \t]*[#!][ \t]*/ " # "

(* View: comment_or_eol
A <comment_eol> or <eol> *)
let comment_or_eol = comment_eol | (del /[ \t]*[#!]?\n/ "\n")

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

(* View: sto_email_addr *)
let sto_email_addr = store Rx.email_addr

(* Variable: word *)
let word = Rx.word

(* Variable: word_slash *)
let word_slash = word | "/"

(* View: sto_word *)
let sto_word = store word

(* View: sto_num *)
let sto_num = store Rx.relinteger

(* View: sto_to_eol *)
let sto_to_eol = store /[^#! \t\n][^#!\n]*[^#! \t\n]|[^#! \t\n]/

(* View: field *)
let field (kw:string) (sto:lens) = indent . Build.key_value_line_comment kw sep_spc sto comment_eol

(* View: flag
A single word *)
let flag (kw:regexp) = [ indent . key kw . comment_or_eol ]

(* View: lens_block
A generic block with a title lens *)
let lens_block (title:lens) (sto:lens) = [ indent . title . opt_eol . lbracket
                                         . (sto | empty | comment)+
                                         . indent . rbracket . eol ]

(* View: block
A simple block with just a block title *)
let block (kw:string) (sto:lens) = lens_block (key kw) sto

(* View: named_block
A block with a block title and name *)
let named_block (kw:string) (sto:lens) = lens_block (key kw . sep_spc . sto_word) sto

(* View: named_block_arg_title
A title lens for named_block_arg *)
let named_block_arg_title (kw:string) (name:string) (arg:string) =
                            key kw . sep_spc
                          . [ label name . sto_word ]
                          . sep_spc
                          . [ label arg . sto_word ]

(* View: named_block_arg
A block with a block title, a name and an argument *)
let named_block_arg (kw:string) (name:string) (arg:string) (sto:lens) =
                           lens_block (named_block_arg_title kw name arg) sto

(************************************************************************
 * Group:                 GLOBAL CONFIGURATION
 *************************************************************************)

(* View: email
A simple email address entry *)
let email = [ indent . label "email" . sto_email_addr . comment_or_eol ]

(* View: global_defs_field
Possible fields in the global_defs block *)
let global_defs_field = block "notification_email" email
                      | field "notification_email_from" sto_email_addr
                      | field "smtp_server" sto_word
                      | field "smtp_connect_timeout" sto_num
                      | field "lvs_id" sto_word
                      | field "router_id" sto_word

(* View: global_defs
A global_defs block *)
let global_defs = block "global_defs" global_defs_field

(* View: prefixlen
A prefix for IP addresses *)
let prefixlen = [ label "prefixlen" . Util.del_str "/" . sto_num ]

(* View: ipaddr
An IP address or range with an optional mask *)
let ipaddr = label "ipaddr" . store /[0-9.-]+/ . prefixlen?

(* View: ipdev
A device for IP addresses *)
let ipdev = [ key "dev" . sep_spc . sto_word ]

(* View: static_ipaddress_field
The whole string is fed to ip addr add.
You can truncate the string anywhere you like and let ip addr add use defaults for the rest of the string.
To be refined with fields according to `ip addr help`.
*)
let static_ipaddress_field = [ indent . ipaddr
                             . (sep_spc . ipdev)?
                             . comment_or_eol ]

(* View: static_routes_field
src $SRC_IP to $DST_IP dev $SRC_DEVICE
*)
let static_routes_field = [ indent . label "route"
                          . [ key "src" . sto_word ] . sep_spc
                          . [ key "to"  . sto_word ] . sep_spc
                          . [ key "dev" . sto_word ] . comment_or_eol ]

(* View: static_routes *)
let static_routes = block "static_ipaddress" static_ipaddress_field
                  | block "static_routes" static_routes_field

(* View: global_conf
A global configuration entry *)
let global_conf = global_defs | static_routes

(************************************************************************
 * Group:                 VRRP CONFIGURATION
 *************************************************************************)

(*View: vrrp_sync_group_field *)
let vrrp_sync_group_field = block "group" [ indent . key word . comment_or_eol ]

(* View: vrrp_sync_group *)
let vrrp_sync_group = named_block "vrrp_sync_group" vrrp_sync_group_field

(* View: vrrp_instance_field *)
let vrrp_instance_field = field "state" sto_word
                        | field "interface" sto_word
                        | field "lvs_sync_daemon_interface" sto_word
                        | field "virtual_router_id" sto_num
                        | field "priority" sto_num
                        | field "advert_int" sto_num
                        | field "garp_master_delay" sto_num
                        | field "notify_master" sto_to_eol
                        | field "notify_backup" sto_to_eol
                        | field "notify_fault" sto_to_eol
                        | flag "smtp_alert"
                        | flag "nopreempt"
                        | flag "ha_suspend"
                        | block "authentication" (
                                field "auth_type" sto_word
                              | field "auth_pass" sto_word
                              )
                        | block "virtual_ipaddress" static_ipaddress_field
                        | block "track_interface" ( flag word )
                        | block "track_script" ( flag word )

(* View: vrrp_instance *)
let vrrp_instance = named_block "vrrp_instance" vrrp_instance_field

(* View: vrrp_script_field *)
let vrrp_script_field = field "script" sto_to_eol
                      | field "interval" sto_num
                      | field "weight" sto_num

(* View: vrrp_script *)
let vrrp_script = named_block "vrrp_script" vrrp_script_field

(* View: vrrpd_conf
contains subblocks of VRRP synchronization group(s) and VRRP instance(s) *)
let vrrpd_conf = vrrp_sync_group | vrrp_instance | vrrp_script

(************************************************************************
 * Group:                 LVS CONFIGURATION
 *************************************************************************)

(* View: tcp_check_field *)
let tcp_check_field = field "connect_timeout" sto_num
                    | field "connect_port" sto_num

(* View: real_server_field *)
let real_server_field = field "weight" sto_num
                      | block "TCP_CHECK" tcp_check_field

(* View: virtual_server_field *)
let virtual_server_field = field "delay_loop" sto_num
                         | field "lb_algo" sto_word
                         | field "lb_kind" sto_word
                         | field "nat_mask" sto_word
                         | field "protocol" sto_word
                         | named_block_arg "real_server" "ip" "port" real_server_field

(* View: virtual_server *)
let virtual_server = named_block_arg "virtual_server" "ip" "port" virtual_server_field

(* View: virtual_server_group_field *)
let virtual_server_group_field = [ indent . label "vip"
                               . [ ipaddr ]
			       . sep_spc
			       . [ label "port" . sto_num ]
			       . comment_or_eol ]

(* View: virtual_server_group *)
let virtual_server_group = named_block "virtual_server_group" virtual_server_group_field

(* View: lvs_conf
contains subblocks of Virtual server group(s) and Virtual server(s) *)
let lvs_conf = virtual_server | virtual_server_group

(* View: lns
     The keepalived lens
*)
let lns = ( empty | comment | global_conf | vrrpd_conf | lvs_conf )*

(* Variable: filter *)
let filter = incl "/etc/keepalived/keepalived.conf"
    . Util.stdexcl

let xfm = transform lns filter


Fix up auditd lens.

Fix up auditd lens.

(* Audit Module lens
Created by Michael Palmiotto *)
module Audit =
  autoload xfm

(* Define commonly used expressions *)
 let equals = del /=[ \t]*/ "= "
 let space = Util.del_ws_spc
 let eol = del /[ \t]*\n/ "\n"
  let comment = Util.comment
  let value_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/

(* Define empty *)
  let empty = [ del /[ \t]*\n/ "" ]

  let control_entry (kw:string) = [ key kw . space . equals . space . value_to_eol . eol ]
  let controls = control_entry "log_file"
                | control_entry "log_format"
                | control_entry "priority_boost"
                | control_entry "flush"
                | control_entry "freq"
                | control_entry "num_logs"
                | control_entry "max_log_file"
                | control_entry "max_log_file_action"
                | control_entry "action_mail_acct"
                | control_entry "space_left"
                | control_entry "space_left_action"
                | control_entry "admin_space_left"
                | control_entry "admin_space_left_action"
                | control_entry "disk_full_action"
                | control_entry "disk_error_action"

  let lns = (comment|empty|control_entry)*
  let filter = incl "/etc/audit/auditd.conf" . excl "#*#" . excl ".*" . Util.stdexcl
  let xfm = transform lns filter

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

(* Audit Module lens
Created by Michael Palmiotto *)
module Audit =
  autoload xfm

(* Define commonly used expressions *)
 let equals = del /=[ \t]*/ "= "
  let eol = del /[ \t]*\n/ "\n"
  let comment = Util.comment
  let value_to_eol = store ( /[^\n]*/ - /([ \t][^\n]*|[^\n]*[ \t])/

(* Define empty *)
  let empty = [ del /[ \t]*\n/ "" ]

  let control_entry (kw:string) = [ key kw . equals . value_to_eol . eol ]
  let controls = control_entry "log_file"
                | control_entry "log_format"
                | control_entry "priority_boost
                | control_entry "flush"
                | control_entry "freq"
                | control_entry "num_logs
                | control_entry "max_log_file"
                | control_entry "max_log_file_action"
                | control_entry "action_mail_acct"
                | control_entry "space_left"
                | control_entry "space_left_action"
                | control_entry "admin_space_left"
                | control_entry "admin_space_left_action"
                | control_entry "disk_full_action"
                | control_entry "disk_error_action"

  let record = [ seq "record" . controls+ ]

  let lns = empty* . ( record . empty )* . record?
  let filter = incl "/etc/audit/auditd.conf" . "Util.stdexcl
  let xfm = transform lns filter

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