Imported Upstream version 1.12.0 upstream/1.12.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Jul 2019 00:21:33 +0000 (09:21 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Jul 2019 00:21:33 +0000 (09:21 +0900)
51 files changed:
AUTHORS
NEWS
configure.ac
doc/naturaldocs/conf/lenses/Menu.txt
examples/Makefile.am
examples/dump.c
examples/fadot.c
lenses/anaconda.aug [new file with mode: 0644]
lenses/devfsrules.aug [new file with mode: 0644]
lenses/dovecot.aug
lenses/hostname.aug
lenses/krb5.aug
lenses/logrotate.aug
lenses/multipath.aug
lenses/nginx.aug
lenses/nsswitch.aug
lenses/pam.aug
lenses/puppetfile.aug
lenses/rsyslog.aug
lenses/semanage.aug [new file with mode: 0644]
lenses/shellvars.aug
lenses/simplevars.aug
lenses/ssh.aug
lenses/sshd.aug
lenses/strongswan.aug
lenses/sudoers.aug
lenses/syslog.aug
lenses/tests/test_anaconda.aug [new file with mode: 0644]
lenses/tests/test_devfsrules.aug [new file with mode: 0644]
lenses/tests/test_dovecot.aug
lenses/tests/test_logrotate.aug
lenses/tests/test_multipath.aug
lenses/tests/test_nginx.aug
lenses/tests/test_pam.aug
lenses/tests/test_puppetfile.aug
lenses/tests/test_rsyslog.aug
lenses/tests/test_semanage.aug [new file with mode: 0644]
lenses/tests/test_shellvars.aug
lenses/tests/test_ssh.aug
lenses/tests/test_strongswan.aug
lenses/tests/test_syslog.aug
lenses/tests/test_toml.aug [new file with mode: 0644]
lenses/tests/test_xorg.aug
lenses/toml.aug [new file with mode: 0644]
lenses/xorg.aug
src/augeas.h
src/augtool.c
src/lexer.l
tests/Makefile.am
tests/root/etc/sysconfig/anaconda [new file with mode: 0644]
tests/root/etc/syslog.conf [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 6b4cfd2..e68ab98 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -147,3 +147,5 @@ Contributions by:
   James Valleroy              <jvalleroy@mailbox.org>
   Pavel Chechetin             <pchechetin@mirantis.com>
   Pedro Valero Mejia          <pedro.valero.mejia@gmail.com>
+  David Farrell               <davidpfarrell+github@gmail.com>
+  Nathan Ward                 <nward@braintrust.co.nz>
diff --git a/NEWS b/NEWS
index 1f42452..f368cb1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,41 @@
+1.12.0 - 2019-04-13
+  - General changes/additions
+    * update gnulib to 91584ed6
+  - Lens changes/additions
+    * Anaconda: new lens to process /etc/sysconfig/anaconda instead of
+                Shellvars (Pino Toscano) (Issue #597)
+    * DevfsRules: add lens for FreeBSD devfs.rules files
+    * Dovecot: permit ! in block titles (Nathan Ward) (Issue #599)
+    * Hostname: Allow creation of hostname when file is missing
+    *           (David Farrell) (Issue #606)
+    * Krb5: add more pkinit_* options (Issue #603)
+    * Logrotate: fix missing recognition of double quoted filenames (Issue #611)
+    * Multipath: accept values enclosed in quotes (Issue #583)
+    * Nginx: support unix sockets as server address (Issue #618)
+    * Nsswitch: add merge action (Issue #609)
+    * Pam: accept continuation lines (Issue #590)
+    * Puppetfile: allow symbols as (optional) values (Issue #619)
+                  allow comments in entries (Issue #620)
+    * Rsyslog: support dynamic file paths (Issue #622)
+               treat #!/+/- as comment (arnolda, PR #595)
+    * Syslog: accept 'include' directive (Issue #486)
+    * Semanage: new lens to process /etc/selinux/semanage.conf instead of
+                Simplevars (Pino Toscano) (Issue #594)
+    * Shellvars: allow and/or in @if conditions (#582)
+                 accept functions wrapped in round brackets,
+                 accept variables with a dash in their name,
+                 exclude csh/tcsh profile scripts (Pino Toscano) (Issue #600)
+                 accept variable as command (Issue #601)
+    * Ssh: accept RekeyLimit (Issue #605)
+    * Sshd: accept '=' to separate option names from their values
+            (Emil Dragu, #587)
+    * Sudoers: support 'always_query_group_plugin' flag (Steve Traylen, #588)
+    * Strongswan: parse lists. This is a backwards-incompatible change
+                  since list entries that were parsed into a single string
+                  are now split into a list of entries (Kaarle Ritvanen)
+    * Toml: new lens to parse .toml files (PR #91)
+    * Xorg: accept empty values for options (arnolda, PR #596)
+
 1.11.0 - 2018-08-24
   - General changes/additions
     * augmatch: add a --quiet option; make the exit status useful to tell
index 11d7ade..6f3a05c 100644 (file)
@@ -1,8 +1,8 @@
-AC_INIT(augeas, 1.11.0)
+AC_INIT(augeas, 1.12.0)
 AC_CONFIG_SRCDIR([src/augeas.c])
 AC_CONFIG_AUX_DIR([build/ac-aux])
 AM_CONFIG_HEADER([config.h])
-AM_INIT_AUTOMAKE([-Wno-portability 1.11 color-tests parallel-tests])
+AM_INIT_AUTOMAKE([-Wno-portability color-tests parallel-tests])
 AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
 
 
@@ -65,8 +65,8 @@ if test x"$enable_debug" = x"yes"; then
 fi
 
 dnl Version info in libtool's notation
-AC_SUBST([LIBAUGEAS_VERSION_INFO], [24:1:24])
-AC_SUBST([LIBFA_VERSION_INFO], [6:2:5])
+AC_SUBST([LIBAUGEAS_VERSION_INFO], [24:2:24])
+AC_SUBST([LIBFA_VERSION_INFO], [6:3:5])
 
 AC_GNU_SOURCE
 
index 190907f..a0b999e 100644 (file)
@@ -209,6 +209,9 @@ Group: Specific Modules  {
    File: Rtadvd  (rtadvd.aug)
    File: Strongswan  (strongswan.aug)
    File: Termcap  (termcap.aug)
+   File: Anaconda  (anaconda.aug)
+   File: Semanage  (semanage.aug)
+   File: Toml  (toml.aug)
    }  # Group: Specific Modules
 
 Group: Generic Modules  {
@@ -315,6 +318,9 @@ Group: Tests and Examples  {
    File: test_slapd.aug  (tests/test_slapd.aug)
    File: test_trapperkeeper.aug  (tests/test_trapperkeeper.aug)
    File: Test_Xymon_Alerting  (tests/test_xymon_alerting.aug)
+   File: Test_Anaconda  (tests/test_anaconda.aug)
+   File: Test_Semanage  (tests/test_semanage.aug)
+   File: test_toml.aug  (tests/test_toml.aug)
    }  # Group: Tests and Examples
 
 Group: Index  {
index 928eb51..0edefbd 100644 (file)
@@ -1,16 +1,12 @@
 
-GNULIB= ../gnulib/lib/libgnu.la
-GNULIB_CFLAGS= -I $(top_srcdir)/gnulib/lib
-
-AM_CFLAGS = @AUGEAS_CFLAGS@ @WARN_CFLAGS@ @LIBXML_CFLAGS@ $(GNULIB_CFLAGS) \
+AM_CFLAGS = @AUGEAS_CFLAGS@ @WARN_CFLAGS@ @LIBXML_CFLAGS@ \
                        -I $(top_srcdir)/src
 
 bin_PROGRAMS = fadot
 noinst_PROGRAMS = dump
 
 fadot_SOURCES = fadot.c
-fadot_LDADD = $(top_builddir)/src/libfa.la $(GNULIB)
+fadot_LDADD = $(top_builddir)/src/libfa.la
 
 dump_sources = dump.c
-dump_LDADD =  $(top_builddir)/src/libaugeas.la $(top_builddir)/src/libfa.la \
-                 $(GNULIB)
+dump_LDADD =  $(top_builddir)/src/libaugeas.la $(top_builddir)/src/libfa.la
index 69a1540..51a3c97 100644 (file)
  *    dump '//descendant::*'
  *
  */
-#define _GNU_SOURCE
 
-#include "config.h"
-#include "augeas.h"
+#include <augeas.h>
 
 #include <stdio.h>
 #include <stdlib.h>
index 666126c..1993ffa 100644 (file)
  * The purpose of this example is to show the usage of libfa
  */
 
-#include <config.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <string.h>
-#include <getopt.h>
 #include <stdlib.h>
 #include <limits.h>
 
-#include "fa.h"
+#include <fa.h>
 
 #define UCHAR_NUM (UCHAR_MAX+1)
 
diff --git a/lenses/anaconda.aug b/lenses/anaconda.aug
new file mode 100644 (file)
index 0000000..8f618db
--- /dev/null
@@ -0,0 +1,30 @@
+(*
+Module: Anaconda
+    Parses Anaconda's user interaction configuration files.
+
+Author: Pino Toscano <ptoscano@redhat.com>
+
+About: Reference
+    https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html
+
+About: Configuration file
+    This lens applies to /etc/sysconfig/anaconda.
+
+About: License
+  This file is licensed under the LGPL v2+, like the rest of Augeas.
+*)
+module Anaconda =
+autoload xfm
+
+let comment = IniFile.comment "#" "#"
+let sep     = IniFile.sep "=" "="
+
+let entry   = IniFile.entry IniFile.entry_re sep comment
+let title   = IniFile.title IniFile.record_re
+let record  = IniFile.record title entry
+
+let lns     = IniFile.lns record comment
+
+let filter  = incl "/etc/sysconfig/anaconda"
+
+let xfm     = transform lns filter
diff --git a/lenses/devfsrules.aug b/lenses/devfsrules.aug
new file mode 100644 (file)
index 0000000..155be76
--- /dev/null
@@ -0,0 +1,24 @@
+module DevfsRules =
+
+  autoload xfm
+
+  let comment  = IniFile.comment IniFile.comment_re "#"
+
+  let eol = Util.eol
+
+  let line_re = /[^][#; \t\n][^#;\n]*[^#; \t\n]/
+  let entry = [ seq "entry" . store line_re . (eol | comment) ]
+
+  let title = Util.del_str "["
+            . key Rx.word . [ label "id" . Sep.equal . store Rx.integer ]
+            . Util.del_str "]" . eol
+            . counter "entry"
+
+  let record = IniFile.record title (entry | comment)
+
+  let lns = IniFile.lns record comment
+
+  let filter = incl "/etc/defaults/devfs.rules"
+            .  incl "/etc/devfs.rules"
+
+  let xfm = transform lns filter
index 72df583..4a25a83 100644 (file)
@@ -114,7 +114,7 @@ let block_newlines (entry:lens) (comment:lens) =
 Map block enclosed in brackets recursively.
 Block may be indented and have optional argument.
 Block body may have entries, comments, empty lines, and nested blocks recursively. *)
-let rec block = [ indent . key block_names . (Sep.space . Quote.do_dquote_opt (store /[\/A-Za-z0-9_-]+/))? . block_newlines (entry|block|mailbox) comment . eol ]
+let rec block = [ indent . key block_names . (Sep.space . Quote.do_dquote_opt (store /!?[\/A-Za-z0-9_-]+/))? . block_newlines (entry|block|mailbox) comment . eol ]
 
 
 (******************************************************************
index 5aa4a65..61cf90b 100644 (file)
@@ -13,7 +13,7 @@ module Hostname =
 autoload xfm
 
 (* View: lns *)
-let lns = [ label "hostname" . store Rx.word . Util.eol ]
+let lns = [ label "hostname" . store Rx.word . Util.eol ] | Util.empty
 
 (* View: filter *)
 let filter = incl "/etc/hostname"
index 734ddde..46c2265 100644 (file)
@@ -85,7 +85,8 @@ let appdefaults =
 let realms =
   let simple_option = /kdc|admin_server|database_module|default_domain/
       |/v4_realm|auth_to_local(_names)?|master_kdc|kpasswd_server/
-      |/admin_server|ticket_lifetime|pkinit_anchors|krb524_server/ in
+      |/admin_server|ticket_lifetime|pkinit_(anchors|identities|identity|pool)/
+      |/krb524_server/ in
   let subsec_option = /v4_instance_convert/ in
   let option = subsec_entry simple_option eq comment in
   let subsec = [ indent . key subsec_option . eq_openbr .
index ceaab95..6709a0a 100644 (file)
@@ -19,7 +19,7 @@ module Logrotate =
    let eol = Util.eol
    let num = Rx.relinteger
    let word = /[^,#= \n\t{}]+/
-   let filename = /\/[^,#= \n\t{}]+/
+   let filename = Quote.do_quote_opt (store /\/[^"',#= \n\t{}]+/)
    let size = num . /[kMG]?/
 
    let indent = del Rx.opt_space "\t"
@@ -112,7 +112,7 @@ module Logrotate =
                  Util.comment
 
    let rule =
-     let filename_entry = [ label "file" . store filename ] in
+     let filename_entry = [ label "file" . filename ] in
      let filename_sep = del /[ \t\n]+/ " " in
      let filenames = Build.opt_list filename_entry filename_sep in
      [ label "rule" . Util.indent . filenames . body . eol ]
index 03dacb5..9db27d0 100644 (file)
@@ -15,13 +15,16 @@ let indent = del /[ \t]*/ ""
 let obr = del /\{([ \t]*)\n/ "{\n"
 let cbr = del /[ \t]*}[ \t]*\n/ "}\n"
 
+(* Like Rx.fspath, but we disallow quotes at the beginning or end *)
+let fspath = /[^" \t\n]|[^" \t\n][^ \t\n]*[^" \t\n]/
+
 let ikey (k:regexp) = indent . key k
 
 let section (n:regexp) (b:lens) =
   [ ikey n . ws . obr . (b|empty|comment)* . cbr ]
 
 let kv (k:regexp) (v:regexp) =
-  [ ikey k . ws . store v . eol ]
+  [ ikey k . ws . del /"?/ "" . store v . del /"?/ "" . eol ]
 
 (* FIXME: it would be much more concise to write                       *)
 (* [ key k . ws . (bare | quoted) ]                                    *)
@@ -56,7 +59,7 @@ let common_setting =
   |qstr /(getuid|prio)_callout/
   (* Settings not documented in `man multipath.conf` *)
   |kv /rr_min_io_rq/ Rx.integer
-  |kv "udev_dir" Rx.fspath
+  |kv "udev_dir" fspath
   |qstr "selector"
   |kv "async_timeout" Rx.integer
   |kv "pg_timeout" Rx.word
@@ -69,7 +72,7 @@ let default_setting =
    common_setting
   |kv "polling_interval" Rx.integer
   |kv "max_polling_interval" Rx.integer
-  |kv "multipath_dir" Rx.fspath
+  |kv "multipath_dir" fspath
   |kv "find_multipaths" /yes|no/
   |kv "verbosity" /[0-6]/
   |kv "reassign_maps" /yes|no/
@@ -79,14 +82,14 @@ let default_setting =
   |kv "fast_io_fail_tmo" (Rx.integer|"off")
   |kv "dev_loss_tmo" (Rx.integer|"infinity")
   |kv "queue_without_daemon" /yes|no/
-  |kv "bindings_file" Rx.fspath
-  |kv "wwids_file" Rx.fspath
+  |kv "bindings_file" fspath
+  |kv "wwids_file" fspath
   |kv "log_checker_err" /once|always/
   |kv "retain_attached_hw_handler" /yes|no/
   |kv "detect_prio" /yes|no/
   |kv "hw_str_match" /yes|no/
   |kv "force_sync" /yes|no/
-  |kv "config_dir" Rx.fspath
+  |kv "config_dir" fspath
   |kv "missing_uev_wait_timeout" Rx.integer
   |kv "ignore_new_boot_devs" /yes|no/
   |kv "retrigger_tries" Rx.integer
index 9c485c1..06989c8 100644 (file)
@@ -56,8 +56,9 @@ let simple =
 (* View: server
      A simple server entry *)
 let server =
-  [ Util.indent . label "@server" . Util.del_str "server"
-  . [ Sep.space . label "@address" . store word ]
+  let address = /[A-Za-z0-9_.:\/-]+/
+  in [ Util.indent . label "@server" . Util.del_str "server"
+  . [ Sep.space . label "@address" . store address ]
   . [ Sep.space . key word . (Sep.equal . store word)? ]*
   . Sep.semicolon
   . (Util.eol|Util.comment_eol) ]
index 5f9e717..ed134b3 100644 (file)
@@ -52,6 +52,7 @@ let reaction =
                 | /[Tt][Rr][Yy][Aa][Gg][Aa][Ii][Nn]/
     in let action_kw = /[Rr][Ee][Tt][Uu][Rr][Nn]/
                      | /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/
+                     | /[Mm][Ee][Rr][Gg][Ee]/
       in let negate = [ Util.del_str "!" . label "negate" ]
         in let reaction_entry = [ label "status" . negate?
                                 . store status_kw
index b1807a0..80cdfb4 100644 (file)
@@ -22,17 +22,22 @@ module Pam =
 
   let eol = Util.eol
   let indent = Util.indent
+  let space = del /([ \t]|\\\\\n)+/ " "
 
   (* For the control syntax of [key=value ..] we could split the key value *)
   (* pairs into an array and generate a subtree control/N/KEY = VALUE      *)
-  let control = /(\[[^]#\n]*\]|[^[ \t][^ \t]*)/
-  let word = /[^# \t\n]+/
+  (* The valid control values if the [...] syntax is not used, is          *)
+  (*   required|requisite|optional|sufficient|include|substack             *)
+  (* We allow more than that because this list is not case sensitive and   *)
+  (* to be more lenient with typos                                         *)
+  let control = /(\[[^]#\n]*\]|[a-zA-Z]+)/
+  let word = /([^# \t\n\\]|\\\\.)+/
   (* Allowed types *)
   let types = /(auth|session|account|password)/i
 
   (* This isn't entirely right: arguments enclosed in [ .. ] can contain  *)
   (* a ']' if escaped with a '\' and can be on multiple lines ('\')       *)
-  let argument = /(\[[^]#\n]+\]|[^[#\n \t][^#\n \t]*)/
+  let argument = /(\[[^]#\n]+\]|[^[#\n \t\\][^#\n \t\\]*)/
 
   let comment = Util.comment
   let comment_or_eol = Util.comment_or_eol
@@ -43,16 +48,16 @@ module Pam =
   (*   @include module                                                     *)
   (* quite a bit                                                           *)
   let include = [ indent . Util.del_str "@" . key "include" .
-                  Util.del_ws_spc . store word . eol ]
+                  space . store word . eol ]
 
   (* Shared with PamConf *)
   let record = [ label "optional" . del "-" "-" ]? .
                [ label "type" . store types ] .
-               Sep.space .
+               space .
                [ label "control" . store control] .
-               Sep.space .
+               space .
                [ label "module" . store word ] .
-               [ Sep.space . label "argument" . store argument ]* .
+               [ space . label "argument" . store argument ]* .
                comment_or_eol
 
   let record_svc = [ seq "record" . indent . record ]
index 89eeb0b..fbd2e81 100644 (file)
@@ -25,31 +25,44 @@ module Puppetfile =
 (* View: comma
      a comma, optionally preceded or followed by spaces or newlines *)
 let comma = del /[ \t\n]*,[ \t\n]*/ ", "
+let comma_nospace = del /[ \t\n]*,/ ","
+
+let comment_or_eol = Util.eol | Util.comment_eol
+let quote_to_comment_or_eol = Quote.do_quote (store /[^#\n]*/) . comment_or_eol
 
 (* View: moduledir
      The moduledir setting specifies where modules from the Puppetfile will be installed *)
-let moduledir = [ Util.indent . key "moduledir" . Sep.space . Quote.any . Util.eol ]
+let moduledir = [ Util.indent . key "moduledir" . Sep.space
+                . quote_to_comment_or_eol ]
 
 (* View: forge
      a forge entry *)
-let forge = [ Util.indent . key "forge" . Sep.space . Quote.any . Util.eol ]
+let forge = [ Util.indent . key "forge" . Sep.space
+            . quote_to_comment_or_eol ]
 
 (* View: metadata
      a metadata entry *)
-let metadata = [ Util.indent . key "metadata" . Util.eol ]
+let metadata = [ Util.indent . key "metadata" . comment_or_eol ]
 
 (* View: mod
      a module entry, with optional version and options *)
 let mod =
      let mod_name = Quote.do_quote (store ((Rx.word . /[\/-]/)? . Rx.word))
-  in let version = [ label "@version" . Quote.do_quote (store /[^:\n]+/) ]
-  in let opt = [ Util.del_str ":" . key Rx.word . del /[ \t]*=>[ \t]*/ " => "
-               . Quote.do_quote (store /[^,\n]*/) ]
-  in let opts = Build.opt_list opt comma
+  in let version = [ label "@version" . Quote.do_quote (store /[^#:\n]+/) . Util.comment_eol? ]
+  in let sto_opt_val = store /[^#"', \t\n][^#"',\n]*[^#"', \t\n]|[^#"', \t\n]/
+  in let opt = [
+                 Util.del_str ":" . key Rx.word
+                 . (del /[ \t]*=>[ \t]*/ " => " . Quote.do_quote_opt sto_opt_val)?
+               ]
+  in let opt_eol = del /([ \t\n]*\n)?/ ""
+  in let opt_space_or_eol = del /[ \t\n]*/ " "
+  in let comma_opt_eol_comment = comma_nospace . (opt_eol . Util.comment_eol)*
+                               . opt_space_or_eol
+  in let opts = Build.opt_list opt comma_opt_eol_comment
   in [ Util.indent . Util.del_str "mod" . seq "mod" . Sep.space . mod_name
-     . (comma . version)?
-     . (comma . opts)?
-     . Util.eol ] 
+     . (comma_opt_eol_comment . version)?
+     . (comma_opt_eol_comment . opts . Util.comment_eol?)?
+     . Util.eol ]
 
 (* View: lns
      the Puppetfile lens *)
index 35f19a5..7b9f7dc 100644 (file)
@@ -49,9 +49,21 @@ let omusrmsg = Util.del_str ":omusrmsg:" .
    File action with a specified template *)
 let file_tmpl = Syslog.file . [ label "template" . Util.del_str ";" . store Rx.word ]
 
+let dynamic = [ Util.del_str "?" . label "dynamic" . store Rx.word ]
+
 let namedpipe = Syslog.pipe . Sep.space . [ label "pipe" . store Syslog.file_r ]
 
-let action = Syslog.action | omusrmsg | file_tmpl | namedpipe
+let action = Syslog.action | omusrmsg | file_tmpl | dynamic | namedpipe
+
+(* Cannot use syslog program because rsyslog does not suppport #! *)
+let program = [ label "program" . Syslog.bang .
+    ( Syslog.opt_plus | [ Build.xchgs "-" "reverse" ] ) .
+    Syslog.programs . Util.eol .  Syslog.entries ]
+
+(* Cannot use syslog hostname because rsyslog does not suppport #+/- *)
+let hostname = [ label "hostname" .
+      ( Syslog.plus | [ Build.xchgs "-" "reverse" ] ) .
+      Syslog.hostnames . Util.eol .  Syslog.entries ]
 
 (* View: entry
    An entry contains selectors and an action
@@ -70,9 +82,9 @@ let prop_filter =
   in [ label "filter" . prop_name . sep . prop_oper . sep . prop_val .
        Sep.space . prop_act . Util.eol ]
 
-let entries = ( Syslog.empty | Syslog.comment | entry | macro | config_object | prop_filter )*
+let entries = ( Syslog.empty | Util.comment | entry | macro | config_object | prop_filter )*
 
-let lns = entries . ( Syslog.program | Syslog.hostname )*
+let lns = entries . ( program | hostname )*
 
 let filter = incl "/etc/rsyslog.conf"
            . incl "/etc/rsyslog.d/*"
diff --git a/lenses/semanage.aug b/lenses/semanage.aug
new file mode 100644 (file)
index 0000000..46f93b3
--- /dev/null
@@ -0,0 +1,37 @@
+(*
+Module: Semanage
+   Parses /etc/selinux/semanage.conf
+
+Author:
+   Pino Toscano <ptoscano@redhat.com>
+
+About: License
+   This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Configuration files
+   This lens applies to /etc/selinux/semanage.conf. See <filter>.
+
+About: Examples
+   The <Test_Semanage> file contains various examples and tests.
+*)
+
+module Semanage =
+  autoload xfm
+
+let comment = IniFile.comment "#" "#"
+let sep = IniFile.sep "=" "="
+let empty = IniFile.empty
+let eol = IniFile.eol
+
+let entry = IniFile.entry IniFile.entry_re sep comment
+          | empty
+
+let title = IniFile.title_label "@group" (IniFile.record_re - /^end$/)
+let record = [ title . entry+ . Util.del_str "[end]" . eol ]
+
+let lns = (entry | record)*
+
+(* Variable: filter *)
+let filter = incl "/etc/selinux/semanage.conf"
+
+let xfm = transform lns filter
index c92d56e..1459d77 100644 (file)
@@ -22,7 +22,7 @@ module Shellvars =
   let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n"
   let brace_eol = del /[ \t\n]+/ "\n"
 
-  let key_re = /[A-Za-z0-9_]+(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export")
+  let key_re = /[A-Za-z0-9_][-A-Za-z0-9_]*(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export")
   let matching_re = "${!" . key_re . /[\*@]\}/
   let eq = Util.del_str "="
 
@@ -153,7 +153,7 @@ module Shellvars =
   let rec command =
        let env = [ key key_re . eq . store anyquot . Sep.cl_or_space ]
     in let reserved_key = /exit|shift|return|ulimit|unset|export|source|\.|if|for|select|while|until|then|else|fi|done|case|eval|alias/
-    in let word = /[A-Za-z0-9_.-\/]+/
+    in let word = /\$?[-A-Za-z0-9_.\/]+/
     in let entry_eol = entry_eol_nocommand | entry_eol_item command
     in let entry_noeol = entry_noeol_nocommand | entry_item command
     in let entry = entry_eol | entry_noeol
@@ -177,7 +177,9 @@ module Shellvars =
   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
+      . sto_to_semicol
+      . ( action_and sto_to_semicol | action_or sto_to_semicol )*
+      . semicol_eol
       . keyword then_kw . eol
       . contents
 
@@ -224,13 +226,13 @@ module Shellvars =
     . entry+
     . Util.indent . Util.del_str "}" . eol ]
 
-  let function (entry:lens) =
+  let function (entry:lens) (start_kw:string) (end_kw:string) =
     [ Util.indent . label "@function"
     . del /(function[ \t]+)?/ ""
     . store Rx.word . del /[ \t]*\(\)/ "()"
-    . (comment_eol|brace_eol) . Util.del_str "{" . brace_eol
+    . (comment_eol|brace_eol) . Util.del_str start_kw . brace_eol
     . entry+
-    . Util.indent . Util.del_str "}" . eol ]
+    . Util.indent . Util.del_str end_kw . eol ]
 
   let rec rec_entry =
     let entry = comment | entry_eol | rec_entry in
@@ -240,7 +242,8 @@ module Shellvars =
       | loop_while entry
       | loop_until entry
       | case entry entry_noeol
-      | function entry
+      | function entry "{" "}"
+      | function entry "(" ")"
       | subshell entry
 
   let lns_norec = del_empty* . (comment | entry_eol) *
@@ -252,6 +255,7 @@ module Shellvars =
 
   let filter_sysconfig =
       sc_incl "*" .
+      sc_excl "anaconda" .
       sc_excl "bootloader" .
       sc_excl "hw-uuid" .
       sc_excl "hwconf" .
@@ -292,6 +296,8 @@ module Shellvars =
                      . excl "/etc/default/whoopsie"
                      . incl "/etc/profile"
                      . incl "/etc/profile.d/*"
+                     . excl "/etc/profile.d/*.csh"
+                     . excl "/etc/profile.d/csh.local"
   let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                      . incl "/etc/conf.d/*"
                      . incl "/etc/cron-apt/config"
index ad9795f..6e6547c 100644 (file)
@@ -46,6 +46,5 @@ let filter = incl "/etc/kernel-img.conf"
            . incl "/etc/audit/auditd.conf"
            . incl "/etc/mixerctl.conf"
            . incl "/etc/wsconsctlctl.conf"
-           . incl "/etc/selinux/semanage.conf"
 
 let xfm = transform lns filter
index 042fc34..4e73158 100644 (file)
@@ -76,6 +76,10 @@ module Ssh =
 
     let global_knownhosts_file = spaces_entry /GlobalKnownHostsFile/i
 
+    let rekey_limit = [ indent . key /RekeyLimit/i . spc_eq .
+                        [ label "amount" . value_to_spc ] .
+                        [ spc . label "duration" . value_to_spc ]? . eol ]
+
     let special_entry = send_env
                            | proxy_command
                            | remote_fw
@@ -84,10 +88,11 @@ module Ssh =
                            | ciphers
                            | algorithms
                            | pubkey_accepted_key_types
-                      | global_knownhosts_file
+                        | global_knownhosts_file
+                        | rekey_limit
 
     let key_re = /[A-Za-z0-9]+/
-               - /SendEnv|Host|ProxyCommand|RemoteForward|LocalForward|MACs|Ciphers|(HostKey|Kex)Algorithms|PubkeyAcceptedKeyTypes|GlobalKnownHostsFile/i
+               - /SendEnv|Host|ProxyCommand|RemoteForward|LocalForward|MACs|Ciphers|(HostKey|Kex)Algorithms|PubkeyAcceptedKeyTypes|GlobalKnownHostsFile|RekeyLimit/i
 
 
     let other_entry = [ indent . key key_re
index 76d7059..1e559ef 100644 (file)
@@ -68,7 +68,7 @@ module Sshd =
 
    let eol = del /[ \t]*\n/ "\n"
 
-   let sep = Util.del_ws_spc
+   let sep = del /[ \t=]+/ " "
 
    let indent = del /[ \t]*/ "  "
 
@@ -80,14 +80,14 @@ module Sshd =
    let empty = Util.empty
 
    let array_entry (kw:regexp) (sq:string) =
-     let bare = Quote.do_quote_opt_nil (store /[^"' \t\n]+/) in
+     let bare = Quote.do_quote_opt_nil (store /[^"' \t\n=]+/) in
      let quoted = Quote.do_quote (store /[^"'\n]*[ \t]+[^"'\n]*/) in
      [ key kw
        . ( [ sep . seq sq . bare ] | [ sep . seq sq . quoted ] )*
        . eol ]
 
    let other_entry =
-     let value = store /[^ \t\n]+([ \t]+[^ \t\n]+)*/ in
+     let value = store /[^ \t\n=]+([ \t=]+[^ \t\n=]+)*/ in
      [ key key_re . sep . value . eol ]
 
    let accept_env = array_entry /AcceptEnv/i "AcceptEnv"
@@ -98,14 +98,14 @@ module Sshd =
    let deny_users = array_entry /DenyUsers/i "DenyUsers"
 
    let subsystemvalue =
-     let value = store (/[^ \t\n](.*[^ \t\n])?/) in
+     let value = store (/[^ \t\n=](.*[^ \t\n=])?/) in
      [ key /[A-Za-z0-9\-]+/ . sep . value . eol ]
 
    let subsystem =
      [ key /Subsystem/i .  sep .  subsystemvalue ]
 
    let list (kw:regexp) (sq:string) =
-     let value = store /[^, \t\n]+/ in
+     let value = store /[^, \t\n=]+/ in
      [ key kw . sep .
          [ seq sq . value ] .
          ([ seq sq . Util.del_str "," . value])* .
@@ -125,7 +125,7 @@ module Sshd =
              | other_entry
 
    let condition_entry =
-    let value = store  /[^ \t\n]+/ in
+    let value = store  /[^ \t\n=]+/ in
     [ sep . key /[A-Za-z0-9]+/ . sep . value ]
 
    let match_cond =
index 69d112b..32b79fa 100644 (file)
@@ -6,7 +6,7 @@ Authors:
   Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>
 
 About: Reference
-  strongswan.conf(5)
+  strongswan.conf(5), swanctl.conf(5)
 
 About: License
   This file is licensed under the LGPL v2+
@@ -19,16 +19,26 @@ autoload xfm
 let ws = del /[\n\t ]*(#[\t ]*\n[\n\t ]*)*/
 
 let rec conf =
-          let name (sep:string) =
-               key (/[^\/.\{\}#\n\t ]+/ - /include/) . Util.del_ws_spc .
-               Util.del_str sep
+          let keys = /[^\/.\{\}#\n\t ]+/ - /include/
+       in let lists = /(crl|oscp)_uris|(local|remote)_(addrs|ts)|vips|pools|(ca)?certs|pubkeys|groups|cert_policy|dns|nbns|dhcp|netmask|server|subnet|split_(in|ex)clude|interfaces_(ignore|use)|preferred/
+       in let proposals = /((ah|esp)_)?proposals/
+       in let name (pat:lens) (sep:string) =
+               pat . Util.del_ws_spc . Util.del_str sep
        in let val = store /[^\n\t ].*/ . Util.del_str "\n" . ws ""
        in let sval = Util.del_ws_spc . val
+       in let ival (pat:lens) (end:string) =
+               Util.del_opt_ws " " . seq "item" . pat . Util.del_str end
+       in let list (l:string) (k:regexp) (v:lens) =
+               [ label l . name (store k) "=" . counter "item" .
+                 [ ival v "," ]* . [ ival v "\n" ] . ws "" ]
+       in let alg = seq "alg" . store /[a-z0-9]+/
 in (
        [ Util.del_str "#" . label "#comment" . Util.del_opt_ws " " . val ] |
        [ key "include" . sval ] |
-       [ name "=" . sval ] |
-       [ name "{" . ws "\n" . conf . Util.del_str "}" . ws "\n" ]
+       [ name (key (keys - lists - proposals)) "=" . sval ] |
+       list "#list" lists (store /[^\n\t ,][^\n,]*/) |
+       list "#proposals" proposals (counter "alg" . [ alg ] . [ Util.del_str "-" . alg ]*) |
+       [ name (key keys) "{" . ws "\n" . conf . Util.del_str "}" . ws "\n" ]
 )*
 
 let lns = ws "" . conf
index 11920d7..043c563 100644 (file)
@@ -316,6 +316,7 @@ let parameter_flag_kw    = "always_set_home" | "authenticate" | "env_editor"
                          | "closefrom_override" | "compress_io" | "fast_glob"
                          | "log_input" | "log_output" | "pwfeedback"
                          | "umask_override" | "use_pty" | "match_group_by_gid"
+                         | "always_query_group_plugin"
 
 let parameter_flag       = [ del_negate . negate_node?
                                . key parameter_flag_kw ]
index 5d9023b..bf5f7b4 100644 (file)
@@ -221,7 +221,7 @@ module Syslog =
        (* View: entries
         entries are either comments/empty lines or entries
         *)
-       let entries = (empty | comment | entry)*
+       let entries = (empty | comment | entry )*
 
        (* Group: Program matching *)
 
@@ -253,10 +253,13 @@ module Syslog =
 
        (* Group: Top of the tree *)
 
+    let include =
+      [ key "include" . sep_tab . store file_r . eol ]
+
        (* View: lns
         generic entries then programs or hostnames matching blocs
         *)
-        let lns = entries . ( program | hostname )*
+        let lns = entries . ( program | hostname | include )*
 
        (* Variable: filter
         all you need is /etc/syslog.conf
diff --git a/lenses/tests/test_anaconda.aug b/lenses/tests/test_anaconda.aug
new file mode 100644 (file)
index 0000000..50b0ac2
--- /dev/null
@@ -0,0 +1,89 @@
+(*
+Module: Test_Anaconda
+  Provides unit tests and examples for the <Anaconda> lens.
+
+  - 'exampleN' snippets are taken from the documentation:
+    https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html
+  - 'installedN' snippets are taken from the resulting files after
+    a successful installation
+*)
+
+module Test_Anaconda =
+
+let example1 = "# comment example - before the section headers
+
+[section_1]
+# comment example - inside section 1
+key_a_in_section1=some_value
+key_b_in_section1=some_value
+
+[section_2]
+# comment example - inside section 2
+key_a_in_section2=some_value
+"
+
+test Anaconda.lns get example1 =
+  { "#comment" = "comment example - before the section headers" }
+  { }
+  { "section_1"
+    { "#comment" = "comment example - inside section 1" }
+    { "key_a_in_section1" = "some_value" }
+    { "key_b_in_section1" = "some_value" }
+    { }
+  }
+  { "section_2"
+    { "#comment" = "comment example - inside section 2" }
+    { "key_a_in_section2" = "some_value" }
+  }
+
+let example2 = "# this is the user interaction config file
+
+[General]
+post_install_tools_disabled=0
+
+[DatetimeSpoke]
+# the date and time spoke has been visited
+visited=1
+changed_timezone=1
+changed_ntp=0
+changed_timedate=1
+
+[KeyboardSpoke]
+# the keyboard spoke has not been visited
+visited=0
+"
+
+test Anaconda.lns get example2 =
+  { "#comment" = "this is the user interaction config file" }
+  { }
+  { "General"
+    { "post_install_tools_disabled" = "0" }
+    { }
+  }
+  { "DatetimeSpoke"
+    { "#comment" = "the date and time spoke has been visited" }
+    { "visited" = "1" }
+    { "changed_timezone" = "1" }
+    { "changed_ntp" = "0" }
+    { "changed_timedate" = "1" }
+    { }
+  }
+  { "KeyboardSpoke"
+    { "#comment" = "the keyboard spoke has not been visited" }
+    { "visited" = "0" }
+  }
+
+let installed1 = "# This file has been generated by the Anaconda Installer 21.48.22.134-1
+
+[ProgressSpoke]
+visited = 1
+
+"
+
+test Anaconda.lns get installed1 =
+  { "#comment" = "This file has been generated by the Anaconda Installer 21.48.22.134-1" }
+  { }
+  { "ProgressSpoke"
+    { "visited" = "1" }
+    { }
+  }
diff --git a/lenses/tests/test_devfsrules.aug b/lenses/tests/test_devfsrules.aug
new file mode 100644 (file)
index 0000000..b27ba6c
--- /dev/null
@@ -0,0 +1,59 @@
+module Test_DevfsRules =
+
+  let manpage_example = "[localrules=10]
+add path 'da*s*' mode 0660 group usb
+"
+
+  test DevfsRules.lns get manpage_example =
+  { "localrules" { "id" = "10" }
+      { "1" = "add path 'da*s*' mode 0660 group usb" } }
+
+
+  let example = "[devfsrules_jail_unhide_usb_printer_and_scanner=30]
+add include $devfsrules_hide_all
+add include $devfsrules_unhide_basic
+add include $devfsrules_unhide_login
+add path 'ulpt*' mode 0660 group printscan unhide 
+add path 'unlpt*' mode 0660 group printscan unhide
+add path 'ugen2.8' mode 0660 group printscan unhide  # Scanner (ugen2.8 is a symlink to usb/2.8.0)
+add path usb unhide
+add path usbctl unhide
+add path 'usb/2.8.0' mode 0660 group printscan unhide
+
+[devfsrules_jail_unhide_usb_scanner_only=30]
+add include $devfsrules_hide_all
+add include $devfsrules_unhide_basic
+add include $devfsrules_unhide_login
+add path 'ugen2.8' mode 0660 group scan unhide  # Scanner
+add path usb unhide
+add path usbctl unhide
+add path 'usb/2.8.0' mode 0660 group scan unhide
+"
+
+  test DevfsRules.lns get example =
+    { "devfsrules_jail_unhide_usb_printer_and_scanner" { "id" = "30" }
+      { "1" = "add include $devfsrules_hide_all" }
+      { "2" = "add include $devfsrules_unhide_basic" }
+      { "3" = "add include $devfsrules_unhide_login" }
+      { "4" = "add path 'ulpt*' mode 0660 group printscan unhide" }
+      { "5" = "add path 'unlpt*' mode 0660 group printscan unhide" }
+      { "6" = "add path 'ugen2.8' mode 0660 group printscan unhide"
+        { "#comment" = "Scanner (ugen2.8 is a symlink to usb/2.8.0)" }
+      }
+      { "7" = "add path usb unhide" }
+      { "8" = "add path usbctl unhide" }
+      { "9" = "add path 'usb/2.8.0' mode 0660 group printscan unhide" }
+      {  }
+    }
+    { "devfsrules_jail_unhide_usb_scanner_only" { "id" = "30" }
+      { "1" = "add include $devfsrules_hide_all" }
+      { "2" = "add include $devfsrules_unhide_basic" }
+      { "3" = "add include $devfsrules_unhide_login" }
+      { "4" = "add path 'ugen2.8' mode 0660 group scan unhide"
+        { "#comment" = "Scanner" }
+      }
+      { "5" = "add path usb unhide" }
+      { "6" = "add path usbctl unhide" }
+      { "7" = "add path 'usb/2.8.0' mode 0660 group scan unhide" }
+    }
+
index 33ea16f..a9b7484 100644 (file)
@@ -523,6 +523,10 @@ mail_attachment_dir =
 mail_attachment_min_size = 128k
 mail_attachment_fs = sis posix
 mail_attachment_hash = %{sha1}
+
+protocol !indexer-worker {
+  mail_vsize_bg_after_count = 0
+}
 "
 test Dovecot.lns get mail_conf =
   { "#comment" = "# Mailbox locations and namespaces" }
@@ -594,6 +598,10 @@ test Dovecot.lns get mail_conf =
   { "mail_attachment_min_size" = "128k" }
   { "mail_attachment_fs" = "sis posix" }
   { "mail_attachment_hash" = "%{sha1}" }
+  {  }
+  { "protocol" = "!indexer-worker"
+    { "mail_vsize_bg_after_count" = "0" }
+  }
 
 
 (* ********************************* master ********************************* *)
index 27e405c..00ba23b 100644 (file)
@@ -14,6 +14,11 @@ test Logrotate.rule get "/var/log/foo /var/log/bar\n{\n monthly\n}\n" =
     { "file" = "/var/log/bar" }
     { "schedule" = "monthly" } }
 
+test Logrotate.rule get "\"/var/log/foo\"\n{\n monthly\n}\n" =
+  { "rule"
+    { "file" = "/var/log/foo" }
+    { "schedule" = "monthly" } }
+
 let conf = "# see man logrotate for details
 # rotate log files weekly
 weekly
index 6e877b0..c32f1d4 100644 (file)
@@ -217,3 +217,31 @@ test Multipath.lns get "blacklist {
     { "device"
       { "vendor" = "SomeCorp" }
       { "product" = "2.5\"\" SSD" } } }
+
+(* Issue #583 - allow optional quotes around values and strip them *)
+test Multipath.lns get "devices {
+  device {
+    vendor \"COMPELNT\"
+    product \"Compellent Vol\"
+    path_grouping_policy \"multibus\"
+    path_checker \"tur\"
+    features \"0\"
+    hardware_handler \"0\"
+    prio \"const\"
+    failback \"immediate\"
+    rr_weight \"uniform\"
+    no_path_retry \"queue\"
+  }
+}\n" =
+  { "devices"
+    { "device"
+      { "vendor" = "COMPELNT" }
+      { "product" = "Compellent Vol" }
+      { "path_grouping_policy" = "multibus" }
+      { "path_checker" = "tur" }
+      { "features" = "0" }
+      { "hardware_handler" = "0" }
+      { "prio" = "const" }
+      { "failback" = "immediate" }
+      { "rr_weight" = "uniform" }
+      { "no_path_retry" = "queue" } } }
index d17b70a..38336b0 100644 (file)
@@ -288,3 +288,12 @@ test lns get "location /foo {
     { "root" = "/var/www/html" }
     { "internal"
       { "#comment" = "only valid in location blocks" } } }
+
+test lns get "upstream php-handler {
+    server unix:/var/run/php/php7.3-fpm.sock;
+}\n" =
+  { "upstream"
+    { "#name" = "php-handler" }
+    { "@server"
+      { "@address" = "unix:/var/run/php/php7.3-fpm.sock" } } }
+
index 9dade7a..187ed2e 100644 (file)
@@ -49,6 +49,25 @@ session    optional     pam_keyinit.so force revoke
       { "argument" = "[motd=/etc/bad example]" }
     }
 
+(* Multiline PAM entries; issue #590 *)
+test Pam.lns get "account \\\ninclude \\\n    system-auth\n" =
+  { "1"
+    { "type" = "account" }
+    { "control" = "include" }
+    { "module" = "system-auth" } }
+
+test Pam.lns get "account\\\n[success=1 default=ignore] \\
+                               pam_succeed_if.so\\\nuser\\\n =\\\nvagrant\\\nuse_uid\\\nquiet\n" =
+ { "1"
+    { "type" = "account" }
+    { "control" = "[success=1 default=ignore]" }
+    { "module" = "pam_succeed_if.so" }
+    { "argument" = "user" }
+    { "argument" = "=" }
+    { "argument" = "vagrant" }
+    { "argument" = "use_uid" }
+    { "argument" = "quiet" } }
+
 (* Local Variables: *)
 (* mode: caml       *)
 (* End:             *)
index 6837b2a..dc46125 100644 (file)
@@ -5,7 +5,7 @@ Module: Test_Puppetfile
 module Test_Puppetfile =
 
 (* Test: Puppetfile.lns *)
-test Puppetfile.lns get "forge \"https://forgeapi.puppetlabs.com\"
+test Puppetfile.lns get "forge \"https://forgeapi.puppetlabs.com\" # the default forge
 
 mod 'puppetlabs-razor'
 mod 'puppetlabs-ntp', \"0.0.3\"
@@ -19,8 +19,9 @@ mod 'puppetlabs-stdlib',
 mod 'puppetlabs-apache', '0.6.0',
   :github_tarball => 'puppetlabs/puppetlabs-apache'
 
-metadata\n" =
-  { "forge" = "https://forgeapi.puppetlabs.com" }
+metadata # we want metadata\n" =
+  { "forge" = "https://forgeapi.puppetlabs.com"
+    { "#comment" = "the default forge" } }
   {  }
   { "1" = "puppetlabs-razor" }
   { "2" = "puppetlabs-ntp"
@@ -40,7 +41,7 @@ metadata\n" =
     { "github_tarball" = "puppetlabs/puppetlabs-apache" }
   }
   {  }
-  { "metadata" }
+  { "metadata" { "#comment" = "we want metadata" } }
 
 (* Test: Puppetfile.lns
      Complex version conditions *)
@@ -63,3 +64,95 @@ test Puppetfile.lns get "mod 'stdlib',
   :git => \"git://github.com/puppetlabs/puppetlabs-stdlib.git\"\n" =
   { "1" = "stdlib"
     { "git" = "git://github.com/puppetlabs/puppetlabs-stdlib.git" } }
+
+
+(* Issue #427 *)
+test Puppetfile.lns get "mod 'puppetlabs/apache', :latest\n" =
+  { "1" = "puppetlabs/apache"
+    { "latest" } }
+
+test Puppetfile.lns get "mod 'data',
+  :git    => 'ssh://git@stash.example.com/bp/puppet-hiera.git',
+  :branch => :control_branch,
+  :default_branch => 'development',
+  :install_path   => '.'\n" =
+  { "1" = "data"
+    { "git" = "ssh://git@stash.example.com/bp/puppet-hiera.git" }
+    { "branch" = ":control_branch" }
+    { "default_branch" = "development" }
+    { "install_path" = "." } }
+
+(* Comment: after module name comma
+    This conflicts with the comma comment tree below *)
+test Puppetfile.lns get "mod 'data' # eol comment\n" = *
+
+(* Comment: after first comma *)
+test Puppetfile.lns get "mod 'data', # eol comment
+  # and another
+  '1.2.3'\n" =
+  { "1" = "data"
+    { "#comment" = "eol comment" }
+    { "#comment" = "and another" }
+    { "@version" = "1.2.3" } }
+
+(* Comment: after version
+    Current culprit: need two \n *)
+test Puppetfile.lns get "mod 'data', '1.2.3' # eol comment\n" = *
+test Puppetfile.lns get "mod 'data', '1.2.3' # eol comment\n\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" { "#comment" = "eol comment" } } }
+
+(* Comment: eol after version comma *)
+test Puppetfile.lns get "mod 'data', '1.2.3', # a comment
+    :local => true\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" }
+    { "#comment" = "a comment" }
+    { "local" = "true" } }
+
+(* Comment: after version comma with newline *)
+test Puppetfile.lns get "mod 'data', '1.2.3',
+ # a comment
+    :local => true\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" }
+    { "#comment" = "a comment" }
+    { "local" = "true" } }
+
+(* Comment: eol before opts, without version *)
+test Puppetfile.lns get "mod 'data', # a comment
+    # :ref => 'abcdef',
+    :local => true\n" =
+  { "1" = "data"
+    { "#comment" = "a comment" }
+    { "#comment" = ":ref => 'abcdef'," }
+    { "local" = "true" } }
+
+(* Comment: after opt comma *)
+test Puppetfile.lns get "mod 'data', '1.2.3',
+    :ref => 'abcdef', # eol comment
+    :local => true\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" }
+    { "ref" = "abcdef" }
+    { "#comment" = "eol comment" }
+    { "local" = "true" } }
+
+(* Comment: in opts *)
+test Puppetfile.lns get "mod 'data', '1.2.3',
+    :ref => 'abcdef',
+    # a comment
+    :local => true\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" }
+    { "ref" = "abcdef" }
+    { "#comment" = "a comment" }
+    { "local" = "true" } }
+
+(* Comment: after last opt *)
+test Puppetfile.lns get "mod 'data', '1.2.3',
+    :local => true # eol comment\n\n" =
+  { "1" = "data"
+    { "@version" = "1.2.3" }
+    { "local" = "true" }
+    { "#comment" = "eol comment" } }
index 5386f83..9011a2b 100644 (file)
@@ -200,8 +200,25 @@ test Rsyslog.lns get "module(load=\"imuxsock\"       # provides support for local s
     { "#comment" = "Turn off message reception via local log socket;" } }
   { "#comment" = "local messages are retrieved through imjournal now." }
 
+(* rsyslog doesn't use bsd-like #! or #+/- specifications *)
+test Rsyslog.lns get "#!prog\n" = { "#comment" = "!prog" }
+test Rsyslog.lns get "#+host\n" = { "#comment" = "+host" }
+test Rsyslog.lns get "#-host\n" = { "#comment" = "-host" }
+
 (* Added in rsyslog 8.33 *)
 test Rsyslog.lns get "include(file=\"/etc/rsyslog.d/*.conf\" mode=\"optional\")\n" =
   { "include"
     { "file" = "/etc/rsyslog.d/*.conf" }
     { "mode" = "optional" } }
+
+(* Dynamic file name template *)
+test Rsyslog.lns get "*.* ?DynamicFile\n" =
+  { "entry"
+    { "selector"
+      { "facility" = "*" }
+      { "level" = "*" }
+    }
+    { "action"
+      { "dynamic" = "DynamicFile" }
+    }
+  }
diff --git a/lenses/tests/test_semanage.aug b/lenses/tests/test_semanage.aug
new file mode 100644 (file)
index 0000000..a6ceaca
--- /dev/null
@@ -0,0 +1,81 @@
+(*
+Module: Test_Semanage
+  Provides unit tests and examples for the <Semanage> lens.
+*)
+
+module Test_Semanage =
+
+(* Variable: phony_conf *)
+let phony_conf = "# this is a comment
+
+mykey = myvalue # eol comment
+anotherkey = another value
+"
+
+(* Test: Semanage.lns *)
+test Semanage.lns get phony_conf =
+   { "#comment" = "this is a comment" }
+   { }
+   { "mykey" = "myvalue"
+     { "#comment" = "eol comment" } }
+   { "anotherkey" = "another value" }
+
+(* Test: Semanage.lns
+   Quotes are OK in variables that do not begin with a quote *)
+test Semanage.lns get "UserParameter=custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'\n" =
+     { "UserParameter" = "custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'" }
+
+(* Test: Semanage.lns
+     Support empty values *)
+test Semanage.lns get "foo =\n" =
+  { "foo" }
+
+(* Variable: conf *)
+let conf = "module-store = direct
+module-store = \"source\"
+
+#policy-version = 19
+
+expand-check=0
+
+usepasswd=False
+bzip-small=true
+bzip-blocksize=5
+ignoredirs=/root
+
+[sefcontext_compile]
+path = /usr/sbin/sefcontext_compile
+args = -r $@
+
+[end]
+
+config=test
+
+[verify module]
+test=value
+[end]
+"
+
+(* Test: Semanage.lns *)
+test Semanage.lns get conf =
+   { "module-store" = "direct" }
+   { "module-store" = "source" }
+   { }
+   { "#comment" = "policy-version = 19" }
+   { }
+   { "expand-check" = "0" }
+   { }
+   { "usepasswd" = "False" }
+   { "bzip-small" = "true" }
+   { "bzip-blocksize" = "5" }
+   { "ignoredirs" = "/root" }
+   { }
+   { "@group" = "sefcontext_compile"
+     { "path" = "/usr/sbin/sefcontext_compile" }
+     { "args" = "-r $@" }
+     { } }
+   { }
+   { "config" = "test" }
+   { }
+   { "@group" = "verify module"
+     { "test" = "value" } }
index e81c7f5..85d8666 100644 (file)
@@ -299,6 +299,13 @@ esac\n" =
     { ".source" = "/tmp/bar" }
   }
 
+  test Shellvars.lns get "foo() (
+  . /tmp/bar
+  )\n" =
+  { "@function" = "foo"
+    { ".source" = "/tmp/bar" }
+  }
+
   (* Dollar assignment *)
   test Shellvars.lns get "FOO=$(bar arg)\n" =
   { "FOO" = "$(bar arg)" }
@@ -450,7 +457,7 @@ esac\n" =
 
   (* Make sure to support empty comments *)
   test lns get "# foo
-  # 
+  #
   #
   foo=bar
   #\n" =
@@ -604,6 +611,9 @@ esac\n" =
   test lns get "alias ls='ls $LS_OPTIONS'\n" =
     { "@alias" = "ls" { "value" = "'ls $LS_OPTIONS'" } }
 
+  test lns get "alias ls-options='ls $LS_OPTIONS'\n" =
+    { "@alias" = "ls-options" { "value" = "'ls $LS_OPTIONS'" } }
+
   (* Allow && and || constructs after condition *)
   test Shellvars.lns get "[ -f $FILENAME ] && do this || or that\n" =
   { "@condition" = "-f $FILENAME"
@@ -614,13 +624,13 @@ esac\n" =
 (* Test: Shellvars.lns
      Parse (almost) any command *)
 test Shellvars.lns get "echo foobar 'and this is baz'
-/usr/local/bin/myscript.sh with args
+/usr/local/bin/myscript-with-dash_and_underscore.sh with args
 echo foo \
 bar\n" =
   { "@command" = "echo"
     { "@arg" = "foobar 'and this is baz'" }
   }
-  { "@command" = "/usr/local/bin/myscript.sh"
+  { "@command" = "/usr/local/bin/myscript-with-dash_and_underscore.sh"
     { "@arg" = "with args" }
   }
   { "@command" = "echo"
@@ -724,7 +734,7 @@ test Shellvars.lns get "{ echo
 }\n" =
   { "@subshell"
     { "@command" = "echo" }
-  } 
+  }
 
 (* One-liner function *)
 test Shellvars.lns get "MyFunc() { echo; }\n" =
@@ -732,6 +742,25 @@ test Shellvars.lns get "MyFunc() { echo; }\n" =
     { "@command" = "echo" }
   }
 
+(* Support and/or in if conditions *)
+test Shellvars.lns get "if [ -f /tmp/file1 ] && [ -f /tmp/file2 ] || [ -f /tmp/file3 ]; then
+  echo foo
+fi
+" =
+  { "@if" = "[ -f /tmp/file1 ]"
+      { "@and" = "[ -f /tmp/file2 ]" }
+      { "@or" = "[ -f /tmp/file3 ]" }
+      { "@command" = "echo"
+          { "@arg" = "foo" }
+      }
+  }
+
+(* Support variable as command *)
+test Shellvars.lns get "$FOO bar\n" =
+  { "@command" = "$FOO"
+      { "@arg" = "bar" }
+  }
+
 
 (*********************************************************
  * Group: Unsupported syntax                             *
index 408901e..f5fca25 100644 (file)
@@ -108,3 +108,13 @@ test Ssh.lns get "ForwardAgent=yes\n" =
 
 test Ssh.lns get "ForwardAgent =\tyes\n" =
  { "ForwardAgent" = "yes" }
+
+(* Issue #605 *)
+test Ssh.lns get "RekeyLimit 1G 1h\n" =
+  { "RekeyLimit"
+    { "amount" = "1G" }
+    { "duration" = "1h" } }
+
+test Ssh.lns get "RekeyLimit 1G\n" =
+  { "RekeyLimit"
+    { "amount" = "1G" } }
index 55fe905..82e960f 100644 (file)
@@ -63,3 +63,64 @@ test Strongswan.lns get "foo { bar = baz\n } quux {}\t#quuux\n" =
   { "foo" { "bar" = "baz" } }
   { "quux" }
   { "#comment" = "quuux" }
+
+
+let connection = "
+
+connections {
+       foo {
+               pools = bar, baz
+               proposals = aes256gcm16-aes128gcm16-ecp512, aes256-sha256-sha1-ecp256-modp4096-modp2048, 3des-md5-modp768
+       }
+       children {
+               bar {
+                       esp_proposals = aes128-sha256-sha1,3des-md5
+               }
+       }
+}
+"
+
+test Strongswan.lns get connection =
+  { "connections"
+    { "foo"
+      { "#list" = "pools"
+        { "1" = "bar" }
+        { "2" = "baz" }
+      }
+      { "#proposals" = "proposals"
+        { "1"
+          { "1" = "aes256gcm16" }
+          { "2" = "aes128gcm16" }
+          { "3" = "ecp512" }
+        }
+        { "2"
+          { "1" = "aes256" }
+          { "2" = "sha256" }
+          { "3" = "sha1" }
+          { "4" = "ecp256" }
+          { "5" = "modp4096" }
+          { "6" = "modp2048" }
+        }
+        { "3"
+          { "1" = "3des" }
+          { "2" = "md5" }
+          { "3" = "modp768" }
+        }
+      }
+    }
+    { "children"
+      { "bar"
+        { "#proposals" = "esp_proposals"
+          { "1"
+            { "1" = "aes128" }
+            { "2" = "sha256" }
+            { "3" = "sha1" }
+          }
+          { "2"
+            { "1" = "3des" }
+            { "2" = "md5" }
+          }
+        }
+      }
+    }
+  }
index 928213e..2621491 100644 (file)
@@ -351,3 +351,6 @@ daemon.info                                     /var/log/cvsupd.log
     (* allow space before comments *)
     test Syslog.lns get "  \t# space comment\n" =
       { "#comment" = "space comment" }
+
+    test Syslog.lns get "include /etc/syslog.d\n" =
+      { "include" = "/etc/syslog.d" }
diff --git a/lenses/tests/test_toml.aug b/lenses/tests/test_toml.aug
new file mode 100644 (file)
index 0000000..29da0ee
--- /dev/null
@@ -0,0 +1,323 @@
+module Test_Toml =
+
+(* Test: Toml.norec
+     String value *)
+test Toml.norec get "\"foo\"" = { "string" = "foo" }
+
+(* Test: Toml.norec
+     Integer value *)
+test Toml.norec get "42" = { "integer" = "42" }
+
+(* Test: Toml.norec
+     Positive integer value *)
+test Toml.norec get "+42" = { "integer" = "+42" }
+
+(* Test: Toml.norec
+     Negative integer value *)
+test Toml.norec get "-42" = { "integer" = "-42" }
+
+(* Test: Toml.norec
+     Large integer value *)
+test Toml.norec get "5_349_221" = { "integer" = "5_349_221" }
+
+(* Test: Toml.norec
+     Hexadecimal integer value *)
+test Toml.norec get "0xDEADBEEF" = { "integer" = "0xDEADBEEF" }
+
+(* Test: Toml.norec
+     Octal integer value *)
+test Toml.norec get "0o755" = { "integer" = "0o755" }
+
+(* Test: Toml.norec
+     Binary integer value *)
+test Toml.norec get "0b11010110" = { "integer" = "0b11010110" }
+
+(* Test: Toml.norec
+     Float value *)
+test Toml.norec get "3.14" = { "float" = "3.14" }
+
+(* Test: Toml.norec
+     Positive float value *)
+test Toml.norec get "+3.14" = { "float" = "+3.14" }
+
+(* Test: Toml.norec
+     Negative float value *)
+test Toml.norec get "-3.14" = { "float" = "-3.14" }
+
+(* Test: Toml.norec
+     Complex float value *)
+test Toml.norec get "-3_220.145_223e-34" = { "float" = "-3_220.145_223e-34" }
+
+(* Test: Toml.norec
+     Inf float value *)
+test Toml.norec get "-inf" = { "float" = "-inf" }
+
+(* Test: Toml.norec
+     Nan float value *)
+test Toml.norec get "-nan" = { "float" = "-nan" }
+
+(* Test: Toml.norec
+     Bool value *)
+test Toml.norec get "true" = { "bool" = "true" }
+
+(* Test: Toml.norec
+     Datetime value *)
+test Toml.norec get "1979-05-27T07:32:00Z" =
+  { "datetime" = "1979-05-27T07:32:00Z" }
+test Toml.norec get "1979-05-27 07:32:00.999999" =
+  { "datetime" = "1979-05-27 07:32:00.999999" }
+
+(* Test: Toml.norec 
+     Date value *)
+test Toml.norec get "1979-05-27" =
+  { "date" = "1979-05-27" }
+
+(* Test: Toml.norec 
+     Time value *)
+test Toml.norec get "07:32:00" =
+  { "time" = "07:32:00" }
+
+(* Test: Toml.norec
+     String value with newline *)
+test Toml.norec get "\"bar\nbaz\"" =
+  { "string" = "bar\nbaz" }
+
+(* Test: Toml.norec
+     Multiline value *)
+test Toml.norec get "\"\"\"\nbar\nbaz\n    \"\"\"" =
+  { "string_multi" = "bar\nbaz" }
+
+(* Test: Toml.norec
+     Literal string value *)
+test Toml.norec get "'bar\nbaz'" =
+  { "string_literal" = "bar\nbaz" }
+
+(* Test: Toml.array_norec
+     Empty array *)
+test Toml.array_norec get "[ ]" =
+  { "array" {} }
+
+(* Test: Toml.array_norec
+     Array of strings *)
+test Toml.array_norec get "[ \"foo\", \"bar\" ]" =
+  { "array" {}
+    { "string" = "foo" } {}
+    { "string" = "bar" } {} }
+
+(* Test: Toml.array_norec
+     Array of arrays *)
+test Toml.array_rec get "[ [ \"foo\", [ 42, 43 ] ], \"bar\" ]" =
+  { "array" {}
+    { "array" {}
+      { "string" = "foo" } {}
+      { "array" {}
+        { "integer" = "42" } {}
+        { "integer" = "43" } {} } {} } {}
+    { "string" = "bar" } {} }
+
+(* Test: Toml.lns
+     Global parameters *)
+test Toml.lns get "# Globals
+foo = \"bar\"\n" =
+  { "#comment" = "Globals" }
+  { "entry" = "foo" { "string" = "bar" } }
+
+(* Test: Toml.lns
+     Simple section/value *)
+test Toml.lns get "[foo]
+bar = \"baz\"\n" =
+  { "table" = "foo" { "entry" = "bar" { "string" = "baz" } } }
+
+(* Test: Toml.lns
+     Subsections *)
+test Toml.lns get "[foo]
+title = \"bar\"
+  [foo.one]
+  hello = \"world\"\n" =
+  { "table" = "foo"
+    { "entry" = "title" { "string" = "bar" } } }
+  { "table" = "foo.one"
+    { "entry" = "hello" { "string" = "world" } } }
+
+(* Test: Toml.lns
+     Nested subsections *)
+test Toml.lns get "[foo]
+[foo.one]
+[foo.one.two]
+bar = \"baz\"\n" =
+  { "table" = "foo" }
+  { "table" = "foo.one" }
+  { "table" = "foo.one.two"
+    { "entry" = "bar" { "string" = "baz" } } }
+
+(* Test: Toml.lns
+     Arrays of tables *)
+test Toml.lns get "[[products]]
+name = \"Hammer\"
+sku = 738594937
+
+[[products]]
+
+[[products]]
+name = \"Nail\"
+sku = 284758393
+color = \"gray\"\n" =
+  { "@table" = "products"
+    { "entry" = "name"
+      { "string" = "Hammer" } }
+    { "entry" = "sku"
+      { "integer" = "738594937" } }
+    {  }
+  }
+  { "@table" = "products"
+    {  }
+  }
+  { "@table" = "products"
+    { "entry" = "name"
+      { "string" = "Nail" } }
+    { "entry" = "sku"
+      { "integer" = "284758393" } }
+    { "entry" = "color"
+      { "string" = "gray" } }
+  }
+
+(* Test: Toml.entry
+     Empty inline table *)
+test Toml.entry get "name = { }\n" =
+  { "entry" = "name"
+    { "inline_table"
+      {  } } }
+
+(* Test: Toml.entry
+     Inline table *)
+test Toml.entry get "name = { first = \"Tom\", last = \"Preston-Werner\" }\n" =
+  { "entry" = "name"
+    { "inline_table" {}
+      { "entry" = "first"
+        { "string" = "Tom"  } } {}
+      { "entry" = "last"
+        { "string" = "Preston-Werner"  } } {} } }
+
+(* Variable: example
+     The example from https://github.com/mojombo/toml *)
+let example = "# This is a TOML document. Boom.
+
+title = \"TOML Example\"
+
+[owner]
+name = \"Tom Preston-Werner\"
+organization = \"GitHub\"
+bio = \"GitHub Cofounder & CEO\nLikes tater tots and beer.\"
+dob = 1979-05-27T07:32:00Z # First class dates? Why not?
+
+[database]
+server = \"192.168.1.1\"
+ports = [ 8001, 8001, 8002 ]
+connection_max = 5000
+enabled = true
+
+[servers]
+
+  # You can indent as you please. Tabs or spaces. TOML don't care.
+  [servers.alpha]
+  ip = \"10.0.0.1\"
+  dc = \"eqdc10\"
+
+  [servers.beta]
+  ip = \"10.0.0.2\"
+  dc = \"eqdc10\"
+  country = \"中国\" # This should be parsed as UTF-8
+
+[clients]
+data = [ [\"gamma\", \"delta\"], [1, 2] ] # just an update to make sure parsers support it
+
+# Line breaks are OK when inside arrays
+hosts = [
+  \"alpha\",
+  \"omega\"
+]
+
+# Products
+
+  [[products]]
+  name = \"Hammer\"
+  sku = 738594937
+
+  [[products]]
+  name = \"Nail\"
+  sku = 284758393
+  color = \"gray\"
+"
+
+test Toml.lns get example =
+  { "#comment" = "This is a TOML document. Boom." } {  }
+  { "entry" = "title"
+    { "string" = "TOML Example" } } {  }
+  { "table" = "owner"
+    { "entry" = "name"
+      { "string" = "Tom Preston-Werner" } }
+    { "entry" = "organization"
+      { "string" = "GitHub" } }
+    { "entry" = "bio"
+      { "string" = "GitHub Cofounder & CEO
+Likes tater tots and beer." }
+    }
+    { "entry" = "dob"
+      { "datetime" = "1979-05-27T07:32:00Z" }
+      { "#comment" = "First class dates? Why not?" } } {  } }
+  { "table" = "database"
+    { "entry" = "server"
+      { "string" = "192.168.1.1" } }
+    { "entry" = "ports"
+      { "array" {  }
+        { "integer" = "8001" } {  }
+        { "integer" = "8001" } {  }
+        { "integer" = "8002" } {  } } }
+    { "entry" = "connection_max"
+      { "integer" = "5000" } }
+    { "entry" = "enabled"
+      { "bool" = "true" } } {  } }
+  { "table" = "servers" {  }
+    { "#comment" = "You can indent as you please. Tabs or spaces. TOML don't care." } }
+  { "table" = "servers.alpha"
+    { "entry" = "ip"
+      { "string" = "10.0.0.1" } }
+    { "entry" = "dc"
+      { "string" = "eqdc10" } } {  } }
+  { "table" = "servers.beta"
+    { "entry" = "ip"
+      { "string" = "10.0.0.2" } }
+    { "entry" = "dc"
+      { "string" = "eqdc10" } }
+    { "entry" = "country"
+      { "string" = "中国" }
+      { "#comment" = "This should be parsed as UTF-8" } } {  } }
+  { "table" = "clients"
+    { "entry" = "data"
+      { "array" {  }
+        { "array"
+          { "string" = "gamma" } {  }
+          { "string" = "delta" } } {  }
+        { "array"
+          { "integer" = "1" } {  }
+          { "integer" = "2" } } {  } }
+      { "#comment" = "just an update to make sure parsers support it" } } {  }
+    { "#comment" = "Line breaks are OK when inside arrays" }
+    { "entry" = "hosts"
+      { "array" {  }
+        { "string" = "alpha" } {  }
+        { "string" = "omega" } {  } } } {  }
+    { "#comment" = "Products" } {  } }
+  { "@table" = "products"
+    { "entry" = "name"
+      { "string" = "Hammer" } }
+    { "entry" = "sku"
+      { "integer" = "738594937" } } {  } }
+  { "@table" = "products"
+    { "entry" = "name"
+      { "string" = "Nail" } }
+    { "entry" = "sku"
+      { "integer" = "284758393" } }
+    { "entry" = "color"
+      { "string" = "gray" } } }
+
index 339435a..86a2829 100644 (file)
@@ -23,6 +23,7 @@ Section \"Device\"
        Option          \"MonitorLayout\" \"LVDS,VGA\"
        VideoRam        229376
         Option          \"NoAccel\"
+        Option          \"fbdev\" \"\"
         Screen          0
 EndSection
 
@@ -68,7 +69,9 @@ EndSection
         { "Option"     = "MonitorLayout"
              { "value"  = "LVDS,VGA" } }
         { "VideoRam"   = "229376" }
-        { "Option"     = "NoAccel" } 
+        { "Option"     = "NoAccel" }
+        { "Option"     = "fbdev"
+             { "value"  = "" } }
         { "Screen"
           { "num" = "0" } } }
      { }
diff --git a/lenses/toml.aug b/lenses/toml.aug
new file mode 100644 (file)
index 0000000..0623653
--- /dev/null
@@ -0,0 +1,145 @@
+(*
+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*
index a1c0dfb..1c87c22 100644 (file)
@@ -72,8 +72,13 @@ let entries_re  = /([oO]ption|[sS]creen|[iI]nput[dD]evice|[dD]river|[sS]ub[sS]ec
 (* Variable: generic_entry_re *)
 let generic_entry_re = /[^# \t\n\/]+/ - entries_re
 
+(* Variable: quoted_non_empty_string_val *)
+let quoted_non_empty_string_val = del "\"" "\"" . store /[^"\n]+/
+                                  . del "\"" "\""
+                                              (* " relax, emacs *)
+
 (* Variable: quoted_string_val *)
-let quoted_string_val = del "\"" "\"" . store /[^"\n]+/ . del "\"" "\""
+let quoted_string_val = del "\"" "\"" . store /[^"\n]*/ . del "\"" "\""
                                               (* " relax, emacs *)
 
 (* Variable: int *)
@@ -117,7 +122,7 @@ let entry_xy (canon:string) (re:regexp) =
  *)
 let entry_str (canon:string) (re:regexp) =
         [ indent . del re canon . label canon
-          . sep_spc . quoted_string_val . eol ]
+          . sep_spc . quoted_non_empty_string_val . eol ]
 
 (* View: entry_generic
  * An entry without a specific handler. Store everything after the keyword,
@@ -128,7 +133,7 @@ let entry_generic  = [ indent . key generic_entry_re
 
 (* View: option *)
 let option = [ indent . del /[oO]ption/ "Option" . label "Option" . sep_spc
-               . quoted_string_val
+               . quoted_non_empty_string_val
                . [ label "value" . sep_spc . quoted_string_val ]*
                . eol ]
 
@@ -137,14 +142,16 @@ let option = [ indent . del /[oO]ption/ "Option" . label "Option" . sep_spc
  *)
 let screen = [ indent . del /[sS]creen/ "Screen" . label "Screen"
                . [ sep_spc . label "num" . store int ]?
-               . ( sep_spc . quoted_string_val
+               . ( sep_spc . quoted_non_empty_string_val
                . [ sep_spc . label "position" . store to_eol ]? )?
                . eol ]
 
 (* View: input_device *)
 let input_device = [ indent . del /[iI]nput[dD]evice/ "InputDevice"
-                     . label "InputDevice" . sep_spc . quoted_string_val
-                     . [ label "option" . sep_spc . quoted_string_val ]*
+                     . label "InputDevice" . sep_spc
+                    . quoted_non_empty_string_val
+                     . [ label "option" . sep_spc
+                        . quoted_non_empty_string_val ]*
                      . eol ]
 
 (* View: driver *)
@@ -169,7 +176,8 @@ let device = entry_str "Device" /[dD]evice/
 
 (* View: display_modes *)
 let display_modes = [ indent . del /[mM]odes/ "Modes" . label "Modes"
-                      . [ label "mode" . sep_spc . quoted_string_val ]+
+                      . [ label "mode" . sep_spc
+                         . quoted_non_empty_string_val ]+
                       . eol ]
 
 (*************************************************************************
index a877079..228a67a 100644 (file)
@@ -66,9 +66,10 @@ extern "C" {
  * Use ROOT as the filesystem root. If ROOT is NULL, use the value of the
  * environment variable AUGEAS_ROOT. If that doesn't exist eitehr, use "/".
  *
- * LOADPATH is a colon-spearated list of directories that modules should be
+ * LOADPATH is a colon-separated list of directories that modules should be
  * searched in. This is in addition to the standard load path and the
- * directories in AUGEAS_LENS_LIB
+ * directories in AUGEAS_LENS_LIB. LOADPATH can be NULL, indicating that
+ * nothing should be added to the load path.
  *
  * FLAGS is a bitmask made up of values from AUG_FLAGS. The flag
  * AUG_NO_ERR_CLOSE can be used to get more information on why
index b05fbfc..b42ef63 100644 (file)
@@ -237,16 +237,26 @@ static char *get_home_dir(uid_t uid) {
     struct passwd pwbuf;
     struct passwd *pw = NULL;
     long val = sysconf(_SC_GETPW_R_SIZE_MAX);
-    size_t strbuflen = val;
 
-    if (val < 0)
-        return NULL;
+    if (val < 0) {
+        // The libc won't tell us how big a buffer to reserve.
+        // Let's hope that 16k is enough (it really should be).
+        val = 16*1024;
+    }
+
+    size_t strbuflen = (size_t) val;
 
     if (ALLOC_N(strbuf, strbuflen) < 0)
         return NULL;
 
     if (getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
         free(strbuf);
+
+        // Try to get the user's home dir from the environment
+        char *env = getenv("HOME");
+        if (env != NULL) {
+            return strdup(env);
+        }
         return NULL;
     }
 
index 78d4a89..d7648bc 100644 (file)
@@ -4,6 +4,7 @@
 %option reentrant noyywrap
 %option warn nodefault
 %option outfile="lex.yy.c" prefix="augl_"
+%option noinput nounput
 
 %top{
 /* config.h must precede flex's inclusion of <stdio.h>
index fb20ffe..54ed71f 100644 (file)
@@ -22,6 +22,7 @@ lens_tests =                  \
   lens-activemq_xml.sh         \
   lens-afs_cellalias.sh                        \
   lens-aliases.sh              \
+  lens-anaconda.sh             \
   lens-anacron.sh              \
   lens-approx.sh               \
   lens-apt_update_manager.sh           \
@@ -58,6 +59,7 @@ lens_tests =                  \
   lens-darkice.sh              \
   lens-debctrl.sh              \
   lens-desktop.sh      \
+  lens-devfsrules.sh \
   lens-device_map.sh    \
   lens-dhclient.sh             \
   lens-dhcpd.sh                \
@@ -186,6 +188,7 @@ lens_tests =                        \
   lens-rx.sh                   \
   lens-samba.sh                        \
   lens-securetty.sh     \
+  lens-semanage.sh             \
   lens-services.sh             \
   lens-shadow.sh               \
   lens-shells.sh               \
@@ -217,6 +220,7 @@ lens_tests =                        \
   lens-thttpd.sh               \
   lens-tmpfiles.sh             \
   lens-trapperkeeper.sh                \
+  lens-toml.sh         \
   lens-tuned.sh                        \
   lens-up2date.sh              \
   lens-updatedb.sh             \
diff --git a/tests/root/etc/sysconfig/anaconda b/tests/root/etc/sysconfig/anaconda
new file mode 100644 (file)
index 0000000..73318cf
--- /dev/null
@@ -0,0 +1,5 @@
+# This file has been generated by the Anaconda Installer 21.48.22.134-1
+
+[ProgressSpoke]
+visited = 1
+
diff --git a/tests/root/etc/syslog.conf b/tests/root/etc/syslog.conf
new file mode 100644 (file)
index 0000000..a137bdc
--- /dev/null
@@ -0,0 +1,38 @@
+# $FreeBSD$
+#
+#      Spaces ARE valid field separators in this file. However,
+#      other *nix-like systems still insist on using tabs as field
+#      separators. If you are sharing this file between systems, you
+#      may want to use only tabs as field separators here.
+#      Consult the syslog.conf(5) manpage.
+*.err;kern.warning;auth.notice;mail.crit               /dev/console
+*.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err  /var/log/messages
+security.*                                     /var/log/security
+auth.info;authpriv.info                                /var/log/auth.log
+mail.info                                      /var/log/maillog
+lpr.info                                       /var/log/lpd-errs
+ftp.info                                       /var/log/xferlog
+cron.*                                         /var/log/cron
+!-devd
+*.=debug                                       /var/log/debug.log
+*.emerg                                                *
+# uncomment this to log all writes to /dev/console to /var/log/console.log
+# touch /var/log/console.log and chmod it to mode 600 before it will work
+#console.info                                  /var/log/console.log
+# uncomment this to enable logging of all log messages to /var/log/all.log
+# touch /var/log/all.log and chmod it to mode 600 before it will work
+#*.*                                           /var/log/all.log
+# uncomment this to enable logging to a remote loghost named loghost
+#*.*                                           @loghost
+# uncomment these if you're running inn
+# news.crit                                    /var/log/news/news.crit
+# news.err                                     /var/log/news/news.err
+# news.notice                                  /var/log/news/news.notice
+# Uncomment this if you wish to see messages produced by devd
+# !devd
+# *.>=notice                                   /var/log/devd.log
+!ppp
+*.*                                            /var/log/ppp.log
+!*
+include                                                /etc/syslog.d
+include                                                /usr/local/etc/syslog.d