Imported Upstream version 1.8.0 35/156135/1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 17 Oct 2017 08:09:21 +0000 (17:09 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 17 Oct 2017 08:09:26 +0000 (17:09 +0900)
Change-Id: I90f0364b08be0538976d5e9ba371dce73b17c0cb
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
36 files changed:
AUTHORS
NEWS
augeas.spec.in
configure.ac
lenses/chrony.aug
lenses/interfaces.aug
lenses/krb5.aug
lenses/multipath.aug
lenses/php.aug
lenses/postfix_virtual.aug
lenses/radicale.aug [new file with mode: 0644]
lenses/rsyslog.aug
lenses/slapd.aug
lenses/ssh.aug
lenses/tests/test_chrony.aug
lenses/tests/test_krb5.aug
lenses/tests/test_postfix_virtual.aug
lenses/tests/test_radicale.aug [new file with mode: 0644]
lenses/tests/test_rsyslog.aug
lenses/tests/test_tmpfiles.aug
lenses/tests/test_xml.aug
lenses/tmpfiles.aug
lenses/xml.aug
lenses/yum.aug
src/Makefile.am
src/augeas.c
src/augeas.h
src/augeas_sym.version
src/augrun.c
src/augtool.c
src/internal.h
src/lens.c
src/syntax.c
src/transform.c
src/xml.c [new file with mode: 0644]
tests/Makefile.am

diff --git a/AUTHORS b/AUTHORS
index 08feb46..35c0d70 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -144,3 +144,4 @@ Contributions by:
   Craig Miskell               <craig@catalyst.net.nz>
   Anton Baranov               <abaranov@linuxfoundation.org>
   Josef Reidinger             <jreidinger@suse.cz>
+  James Valleroy              <jvalleroy@mailbox.org>
diff --git a/NEWS b/NEWS
index df0943f..7240677 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,40 @@
+1.8.0 - 2017-03-20
+  - General changes/additions
+    * augtool: add a 'source' command exposing the aug_source API call
+    * augtool: add a 'context' command to make changing into a node more
+      discoverable
+    * augtool: add an 'info' command to print important information
+    * augtool: dramatically reduce memory consumption when all lenses are
+      loaded by more aggressively releasing temporary data structures.  On
+      my machine, maximum memory usage of 'augtool -L' drops from roughly
+      90MB to about 20MB. This will not change the amount of memory used
+      when only specific lenses are used, only the default behavior of
+      loading all lenses, i.e., when -A is not passed.
+    * make building augtool statically possible (Jörg Krause)
+    * split aug_to_xml into its own source file, so that statically linking
+      against libaugeas.a doesn't require also linking against libXml2 and
+      its dependencies, provided aug_to_xml is not needed.
+  - API changes
+    * add aug_source to find the source file for a particular node
+    * reduce memory consumption when AUG_NO_MODL_AUTOLOAD is _not_ passed;
+      exact same details as described above for augtool
+  - Lens changes/additions
+    * Chrony: allow floating point numbers (Miroslav Lichvar)
+              add new directives from chrony 3.0 and 3.1 (Miroslav Lichvar)
+    * Krb5: support include/includedir directives (Jason Smith) (Issue #430)
+            support realms that start with numbers (Dustin Wheeler) (Issue #437)
+    * Multipath: update to multipath-0.4.9-99.el7 (Xavier Mol)
+    * Php: also look for FPM files in /etc/php/*/fpm/pool.d (Daniel Dico)
+    * Postfix_virtual: allow underscores in e-mail addresses (Jason Lingohr)
+                       (Issue #439)
+    * Radicale: new lens for config of http://radicale.org/ (James Valleroy)
+    * Rsyslog: support multiple options in module statements (Craig Miskell)
+    * Ssh: also look for files in in /etc/ssh/ssh_config.d (Ian Mortimer)
+    * Tmpfiles: parse 'q'/'Q' modes, parse two-character arguments,
+                parse three-digit file modes
+    * Xml: support external entity declarations in the doctype (Issue #142)
+    * Yum: also read DNF files from /etc/dnf (Pat Riehecky) (Issue #434)
+
 1.7.0 - 2016-11-08
   - General changes/additions
     * allow multiple transforms handling the same file as long as they
index 5a829e2..fd0d553 100644 (file)
@@ -7,12 +7,11 @@ Group:          System Environment/Libraries
 License:        LGPLv2+
 URL:            http://augeas.net/
 Source0:        http://download.augeas.net/%{name}-%{version}.tar.gz
+
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 BuildRequires:  readline-devel libselinux-devel libxml2-devel
 Requires:       %{name}-libs = %{version}-%{release}
-# Bundling exception for gnulib: https://fedorahosted.org/fpc/ticket/174
-Provides:       bundled(gnulib)
 
 %description
 A library for programmatically editing configuration files. Augeas parses
@@ -47,11 +46,26 @@ configuration files into a tree structure, which it exposes through its
 public API. Changes made through the API are written back to the initially
 read files.
 
+%package        static
+Summary:        Static libraries for %{name}
+Group:          Development/Libraries
+Requires:       %{name}-devel = %{version}-%{release}
+
+%description    static
+The %{name}-static package contains static libraries needed to produce
+static builds using %{name}.
+
+
+
 %prep
 %setup -q
 
 %build
-%configure --disable-static
+%configure \
+%ifarch riscv64
+    --disable-gnulib-tests \
+%endif
+    --enable-static
 make %{?_smp_mflags}
 
 %check
@@ -92,7 +106,7 @@ rm -rf $RPM_BUILD_ROOT
 
 %files libs
 %defattr(-,root,root,-)
-# %{_datadir}/augeas and %{_datadir}/augeas/lenses are owned
+# _datadir/augeas and _datadir/augeas/lenses are owned
 # by filesystem.
 %{_datadir}/augeas/lenses/dist
 %{_libdir}/*.so.*
@@ -105,35 +119,114 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/*.so
 %{_libdir}/pkgconfig/augeas.pc
 
+%files static
+%defattr(-,root,root,-)
+%{_libdir}/libaugeas.a
+%{_libdir}/libfa.a
+
 %changelog
-* Tue Oct 15 2013 Dominic Cleal <dcleal@redhat.com> - 1.1.0-2
-- Add %check stage to run make check (rjones@redhat.com)
-- Don't package lenses in tests/ subdirectory (rjones@redhat.com)
-- Fix source URL to download.augeas.net (RHBZ#996033)
+* Fri Mar 17 2017 David Lutterkort <lutter@watzmann.net> - 1.8.0-1
+- add static subpackage
 
-* Fri Jun 14 2013 David Lutterkort <lutter@watzmann.net> - 1.1.0-1
-- New version
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.0-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
 
-* Fri Dec 21 2012 David Lutterkort <lutter@redhat.com> - 1.0.0-1
-- New version
+* Thu Jan 12 2017 Igor Gnatenko <ignatenko@redhat.com> - 1.7.0-3
+- Rebuild for readline 7.x
+
+* Sat Nov 12 2016 Richard W.M. Jones <rjones@redhat.com> - 1.7.0-2
+- riscv64: Disable gnulib tests on riscv64 architecture.
+
+* Wed Nov 09 2016 Dominic Cleal <dominic@cleal.org> - 1.7.0-1
+- Update to 1.7.0
+
+* Mon Aug 08 2016 Dominic Cleal <dominic@cleal.org> - 1.6.0-1
+- Update to 1.6.0
+
+* Thu May 12 2016 Dominic Cleal <dominic@cleal.org> - 1.5.0-1
+- Update to 1.5.0
+
+* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.4.0-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.4.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Tue Jun 02 2015 Dominic Cleal <dcleal@redhat.com> - 1.4.0-1
+- Update to 1.4.0
+
+* Sat Nov 08 2014 Dominic Cleal <dcleal@redhat.com> - 1.3.0-1
+- Update to 1.3.0; remove all patches
+
+* Fri Aug 15 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.0-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Mon Mar 31 2014 Dominic Cleal <dcleal@redhat.com> - 1.2.0-2
+- Add patch for Krb5, parse braces in values (RHBZ#1079444)
+
+* Wed Feb 12 2014 Dominic Cleal <dcleal@redhat.com> - 1.2.0-1
+- Update to 1.2.0, add check section
+- Update source URL to download.augeas.net (RHBZ#996032)
+
+* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Wed Jun 19 2013 David Lutterkort <lutter@redhat.com> - 1.1.0-1
+- Update to 1.1.0; remove all patches
+
+* Tue Jun 18 2013 Richard W.M. Jones <rjones@redhat.com> - 1.0.0-4
+- Fix /etc/sysconfig/network (RHBZ#904222).
+
+* Wed Jun  5 2013 Richard W.M. Jones <rjones@redhat.com> - 1.0.0-3
+- Don't package lenses in tests/ subdirectory.
+
+* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.0.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Fri Jan  4 2013 David Lutterkort <lutter@redhat.com> - 1.0.0-1
+- New version; remove all patches
+
+* Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.10.0-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Tue Jan 10 2012 David Lutterkort <lutter@redhat.com> - 0.10.0-3
+- Add patches for bugs 247 and 248 (JSON lens)
+
+* Sat Dec  3 2011 Richard W.M. Jones <rjones@redhat.com> - 0.10.0-2
+- Add patch to resolve missing libxml2 requirement in augeas.pc.
 
 * Fri Dec  2 2011 David Lutterkort <lutter@redhat.com> - 0.10.0-1
 - New version
 
 * Mon Jul 25 2011 David Lutterkort <lutter@redhat.com> - 0.9.0-1
-- New version
+- New version; removed patch pathx-whitespace-ea010d8
+
+* Tue May  3 2011 David Lutterkort <lutter@redhat.com> - 0.8.1-2
+- Add patch pathx-whitespace-ea010d8.patch to fix BZ 700608
 
 * Fri Apr 15 2011 David Lutterkort <lutter@redhat.com> - 0.8.1-1
 - New version
 
-* Tue Feb 22 2011 David Lutterkort <lutter@redhat.com> - 0.8.0-1
+* Wed Feb 23 2011 David Lutterkort <lutter@redhat.com> - 0.8.0-1
 - New version
 
-* Fri Nov 19 2010 David Lutterkort <lutter@redhat.com> - 0.7.4-1
-- New version
+* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Nov 22 2010 Matthew Booth <mbooth@redhat.com> - 0.7.4-1
+- Update to version 0.7.4
+
+* Thu Nov 18 2010 Richard W.M. Jones <rjones@redhat.com> - 0.7.3-2
+- Upstream patch proposed to fix GCC optimization bug (RHBZ#651992).
 
 * Fri Aug  6 2010 David Lutterkort <lutter@redhat.com> - 0.7.3-1
-- New version
+- Remove upstream patches
+
+* Tue Jun 29 2010 David Lutterkort <lutter@redhat.com> - 0.7.2-2
+- Patches based on upstream fix for BZ 600141
 
 * Tue Jun 22 2010 David Lutterkort <lutter@redhat.com> - 0.7.2-1
 - Fix ownership of /usr/share/augeas. BZ 569393
@@ -142,13 +235,22 @@ rm -rf $RPM_BUILD_ROOT
 - New version
 
 * Thu Jan 14 2010 David Lutterkort <lutter@redhat.com> - 0.7.0-1
-- New version
+- Remove patch vim-ftdetect-syntax.patch. It's upstream
+
+* Tue Dec 15 2009 David Lutterkort <lutter@redhat.com> - 0.6.0-2
+- Fix ftdetect file for vim
 
 * Mon Nov 30 2009 David Lutterkort <lutter@redhat.com> - 0.6.0-1
 - Install vim syntax files
 
 * Mon Sep 14 2009 David Lutterkort <lutter@redhat.com> - 0.5.3-1
-- New version
+- Remove separate xorg.aug, included in upstream source
+
+* Tue Aug 25 2009 Matthew Booth <mbooth@redhat.com> - 0.5.2-3
+- Include new xorg lens from upstream
+
+* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.5.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
 
 * Mon Jul 13 2009 David Lutterkort <lutter@redhat.com> - 0.5.2-1
 - New version
index 25da6be..bbdfdf1 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(augeas, 1.7.0)
+AC_INIT(augeas, 1.8.0)
 AC_CONFIG_SRCDIR([src/augeas.c])
 AC_CONFIG_AUX_DIR([build/ac-aux])
 AM_CONFIG_HEADER([config.h])
@@ -65,7 +65,7 @@ if test x"$enable_debug" = x"yes"; then
 fi
 
 dnl Version info in libtool's notation
-AC_SUBST([LIBAUGEAS_VERSION_INFO], [21:1:21])
+AC_SUBST([LIBAUGEAS_VERSION_INFO], [22:0:22])
 AC_SUBST([LIBFA_VERSION_INFO], [5:4:4])
 
 AC_GNU_SOURCE
index 783fc9f..2792ced 100644 (file)
@@ -58,7 +58,7 @@ module Chrony =
  * Group: Create required expressions
  ************************************************************************)
     (* Variable: number *)
-    let number = integer | decimal
+    let number = integer | decimal | decimal . /[eE]/ . integer
 
     (* Variable: address_re *)
     let address_re = Rx.ip | Rx.hostname
@@ -83,6 +83,7 @@ module Chrony =
                     | /(min|max)poll/
                     | /(min|max)samples/
                     | "maxsources"
+                    | "offset"
                     | "polltarget"
                     | "port"
                     | "presend"
@@ -92,7 +93,7 @@ module Chrony =
          Server/Peer/Pool options without values
     *)
     let cmd_flags = "auto_offline"|"iburst"|"noselect"|"offline"|"prefer"
-                    |"require"|"trust"
+                  |"require"|"trust"|"xleave"
 
     (* Variable: ntp_source
          Server/Peer/Pool key names
@@ -104,6 +105,16 @@ module Chrony =
     *)
     let allowdeny_types = "allow"|"deny"|"cmdallow"|"cmddeny"
 
+    (* Variable: hwtimestamp_options
+         HW timestamping options with values
+    *)
+    let hwtimestamp_options = "minpoll"|"precision"|"rxcomp"|"txcomp"
+
+    (* Variable: hwtimestamp_flags
+         HW timestamping options without values
+    *)
+    let hwtimestamp_flags = "nocrossts"
+
     (* Variable: local_options
          local options with values
     *)
@@ -145,7 +156,8 @@ module Chrony =
     (* Variable: log_flags
         log has a specific options list
     *)
-    let log_flags = /measurements|statistics|tracking|rtc|refclocks|tempcomp/
+    let log_flags = "measurements"|"rawmeasurements"|"refclocks"|"rtc"
+                  |"statistics"|"tempcomp"|"tracking"
 
     (* Variable: simple_keys
          Options with single values
@@ -157,9 +169,10 @@ module Chrony =
                     | "dumpdir" | "hwclockfile" | "include" | "keyfile"
                     | "leapsecmode" | "leapsectz" | "linux_freq_scale"
                     | "linux_hz" | "logbanner" | "logchange" | "logdir"
-                    | "maxdistance" | "maxdrift"
-                    | "maxclockerror" | "maxsamples" | "maxslewrate"
-                    | "maxupdateskew" | "minsamples" | "minsources" | "pidfile"
+                    | "maxclockerror" | "maxdistance" | "maxdrift"
+                    | "maxjitter" | "maxsamples" | "maxslewrate"
+                    | "maxupdateskew" | "minsamples" | "minsources"
+                    | "ntpsigndsocket" | "pidfile"
                     | "port" | "reselectdist" | "rtcautotrim" | "rtcdevice"
                     | "rtcfile" | "sched_priority" | "stratumweight" | "user"
 
@@ -169,7 +182,7 @@ module Chrony =
     (* View: host_flags *)
     let host_flags = [ space . key cmd_flags ]
     (* View: host_options *)
-    let host_options = [ space . key cmd_options . space . store integer ]
+    let host_options = [ space . key cmd_options . space . store number ]
     (* View: log_flag_list *)
     let log_flag_list = [ space . key log_flags ]
     (* View: store_address *)
@@ -196,6 +209,7 @@ module Chrony =
       - log <options>
       - broadcast <interval> <address> <optional port>
       - fallbackdrift <min> <max>
+      - hwtimestamp <interface> <options>
       - initstepslew <threshold> <addr> <optional extra addrs>
       - local <options>
       - mailonchange <emailaddress> <threshold>
@@ -245,6 +259,15 @@ module Chrony =
                       . space . [ label "max" . store integer ]
                       . eol ]
 
+    (* View: hwtimestamp
+         hwtimestamp has specific syntax
+    *)
+    let hwtimestamp = [ Util.indent . key "hwtimestamp"
+                      . space . [ label "interface" . store no_space ]
+                      . ( space . ( [ key hwtimestamp_flags ]
+                         | [ key hwtimestamp_options . space . store number ] )
+                        )*
+                      . eol ]
     (* View: istepslew
          initstepslew has specific syntax
     *)
@@ -348,7 +371,7 @@ module Chrony =
  *)
 let settings = host_list | allowdeny | log_list | bcast | fdrift | istepslew
              | local | email | makestep | maxchange | refclock | smoothtime
-             | ratelimit | tempcomp | kv | all_flags
+             | hwtimestamp | ratelimit | tempcomp | kv | all_flags
 
 (*
  * View: lns
index 4d68a62..fed982e 100644 (file)
@@ -1,4 +1,4 @@
-(* Intefraces module for Augeas
+(* Interfaces module for Augeas
  Author: Free Ekanayaka <free@64studio.com>
 
  Reference: man interfaces
@@ -36,7 +36,7 @@ let empty      = Util.empty
 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 and multi-value options*)
+(* Define reserved words and multi-value options *)
 let stanza_word =
    /(source(-directory)?|iface|auto|allow-[a-z-]+|mapping|bond-slaves|bridge-ports)/
 
@@ -113,7 +113,7 @@ let source_directory = [ key "source-directory" . sep_spc . sto_to_eol ]
    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 *)
+   of an iface or mapping block *)
 
 let stanza_single = (auto|allow|source|source_directory) . (comment|empty)*
 let stanza_multi  = iface|mapping
index 37778fd..734ddde 100644 (file)
@@ -21,8 +21,8 @@ let closebr = del /[ \t]*\}/ "}"
    and realms in the [appdefaults] section.
 *)
 
-let realm_re = /[A-Z][.a-zA-Z0-9-]*/
-let realm_anycase_re = /[A-Za-z][.a-zA-Z0-9-]*/
+let realm_re = /[A-Z0-9][.a-zA-Z0-9-]*/
+let realm_anycase_re = /[A-Za-z0-9][.a-zA-Z0-9-]*/
 let app_re = /[a-z][a-zA-Z0-9_]*/
 let name_re = /[.a-zA-Z0-9_-]+/
 
@@ -151,8 +151,13 @@ let kdc =
 let pam =
   simple_section "pam" name_re
 
-let lns = (comment|empty)* .
+let includes = Build.key_value_line /include(dir)?/ Sep.space (store Rx.fspath)
+
+let lns = (comment|empty|includes)* .
   (libdefaults|login|appdefaults|realms|domain_realm
   |logging|capaths|dbdefaults|dbmodules|instance_mapping|kdc|pam)*
 
-let xfm = transform lns (incl "/etc/krb5.conf")
+let filter = (incl "/etc/krb5.conf.d/*.conf")
+           . (incl "/etc/krb5.conf")
+
+let xfm = transform lns filter
index 62d7f81..ba0e8ce 100644 (file)
@@ -37,68 +37,74 @@ let wwid = kv "wwid" (Rx.word|"*")
 
 (* Settings that can be changed in various places *)
 let common_setting =
-  kv "path_grouping_policy"
-    /failover|multibus|group_by_(serial|prio|node_name)/
- |qstr /(getuid|prio)_callout/
- |qstr /path_(selector|checker)|features/
- |kv "failback" (Rx.integer | /immediate|manual/)
- |kv "rr_weight" /priorities|uniform/
- |kv "no_path_retry" (Rx.integer | /fail|queue/)
- |kv /rr_min_io(_rq)?/ Rx.integer
- |kv "flush_on_last_del" /yes|no/
- |kv "reservation_key" Rx.word
- |kv "delay_watch_checks" (Rx.integer|"no")
- |kv "delay_wait_checks" (Rx.integer|"no")
-
-let default_setting =
-  kv "polling_interval" Rx.integer
+   qstr "path_selector"
+  |kv "path_grouping_policy" /failover|multibus|group_by_(serial|prio|node_name)/
+  |kv "path_checker" /tur|emc_clariion|hp_sw|rdac|directio|rdb|readsector0/
+  |kv "prio" /const|emc|alua|ontap|rdac|hp_sw|hds|random|weightedpath/
+  |qstr "prio_args"
+  |kv "failback" (Rx.integer | /immediate|manual|followover/)
+  |kv "rr_weight" /priorities|uniform/
+  |kv "flush_on_last_del" /yes|no/
+  |kv "user_friendly_names" /yes|no/
+  |kv "no_path_retry" (Rx.integer | /fail|queue/)
+  |kv /rr_min_io(_q)?/ Rx.integer
+  |qstr "features"
+  |kv "reservation_key" Rx.word
+  |kv "deferred_remove" /yes|no/
+  |kv "delay_watch_checks" (Rx.integer | "no")
+  |kv "delay_wait_checks" (Rx.integer | "no")
+  |kv "skip_kpartx" /yes|no/
+  (* Deprecated settings for backwards compatibility *)
+  |qstr /(getuid|prio)_callout/
+  (* Settings not documented in `man multipath.conf` *)
+  |kv /rr_min_io_rq/ Rx.integer
   |kv "udev_dir" Rx.fspath
   |qstr "selector"
-  |kv "user_friendly_names" /yes|no/
-  |kv "dev_loss_tmo" Rx.integer
-  |kv "fast_io_fail_tmo" Rx.integer
-  |kv "verbosity" /[0-6]/
-  |kv "reassign_maps" /yes|no/
-  |kv "prio" Rx.word
-  |kv "max_fds" Rx.integer
-  |kv "find_multipaths" /yes|no/
-  |kv "checker_timeout" Rx.integer
-  |kv "hwtable_regex_match" /yes|no/
-  |kv "reload_readwrite" /yes|no/
-  |kv "replace_wwid_whitespace" /yes|no/
-  |kv "force_sync" /yes|no/
-  |kv "config_dir" Rx.fspath
-  (* SUSE extensions *)
   |kv "async_timeout" Rx.integer
-  |kv "max_polling_interval" Rx.integer
   |kv "pg_timeout" Rx.word
-  |kv "bindings_file" Rx.fspath
-  |kv "multipath_dir" Rx.fspath
-  |kv "alias_prefix" Rx.word
-  |kv "queue_without_daemon" /yes|no/
   |kv "h_on_last_deleassign_maps" /yes|no/
-  |qstr "prio_args"
-  (* SUSE extensions SP3 *)
   |qstr "uid_attribute"
+  |kv "hwtable_regex_match" /yes|no|on|off/
+  |kv "reload_readwrite" /yes|no/
+
+let default_setting =
+   common_setting
+  |kv "polling_interval" Rx.integer
+  |kv "max_polling_interval" Rx.integer
+  |kv "multipath_dir" Rx.fspath
+  |kv "find_multipaths" /yes|no/
+  |kv "verbosity" /[0-6]/
+  |kv "reassign_maps" /yes|no/
+  |kv "uid_attrribute" Rx.word
+  |kv "max_fds" (Rx.integer|"max")
+  |kv "checker_timeout" Rx.integer
+  |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 "log_checker_err" Rx.word
+  |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 "missing_uev_wait_timeout" Rx.integer
+  |kv "ignore_new_boot_devs" /yes|no/
+  |kv "retrigger_tries" Rx.integer
+  |kv "retrigger_delay" Rx.integer
+  |kv "new_bindings_in_boot" /yes|no/
 
 (* A device subsection *)
 let device =
   let setting =
-    qstr /vendor|product|product_blacklist|hardware_handler/
-   |common_setting
+    qstr /vendor|product|product_blacklist|hardware_handler|alias_prefix/
    |default_setting in
   section "device" setting
 
 (* The defaults section *)
 let defaults =
-  let setting =
-    common_setting
-   |default_setting
-  in section "defaults" setting
+  section "defaults" default_setting
 
 (* The blacklist and blacklist_exceptions sections *)
 let blacklist =
index fa5bec5..2254bab 100644 (file)
@@ -52,6 +52,7 @@ let filter = (incl "/etc/php*/*/*.ini")
              . (incl "/etc/php.d/*.ini")
              (* PHPFPM Support *)
              . (incl "/etc/php*/fpm/pool.d/*.conf")
+             . (incl "/etc/php/*/fpm/pool.d/*.conf")             
              (* Zend Community edition *)
              . (incl "/usr/local/zend/etc/php.ini")
              . (incl "/usr/local/zend/etc/conf.d/*.ini")
index bb6cbae..69581e0 100644 (file)
@@ -32,7 +32,7 @@ let space_or_eol (sep:regexp) (default:string) =
   del (space_or_eol_re? . sep . space_or_eol_re?) default
 
 (* View: word *)
-let word = store /[A-Za-z0-9@\*.+=-]+/
+let word = store /[A-Za-z0-9@\*.+=_-]+/
 
 (* View: comma *)
 let comma = space_or_eol "," ", "
diff --git a/lenses/radicale.aug b/lenses/radicale.aug
new file mode 100644 (file)
index 0000000..7e50e69
--- /dev/null
@@ -0,0 +1,44 @@
+(* Radicale module for Augeas
+ Based on Puppet lens.
+
+ Manage config file for http://radicale.org/
+ /etc/radicale/config is a standard INI File.
+*)
+
+
+module Radicale =
+  autoload xfm
+
+(************************************************************************
+ * INI File settings
+ *
+ * /etc/radicale/config only supports "#" as commentary and "=" as separator
+ *************************************************************************)
+let comment    = IniFile.comment "#" "#"
+let sep        = IniFile.sep "=" "="
+
+
+(************************************************************************
+ *                        ENTRY
+ * /etc/radicale/config uses standard INI File entries
+ *************************************************************************)
+let entry   = IniFile.indented_entry IniFile.entry_re sep comment
+
+
+(************************************************************************
+ *                        RECORD
+ * /etc/radicale/config uses standard INI File records
+ *************************************************************************)
+let title   = IniFile.indented_title IniFile.record_re
+let record  = IniFile.record title entry
+
+
+(************************************************************************
+ *                        LENS & FILTER
+ * /etc/radicale/config uses standard INI File records
+ *************************************************************************)
+let lns     = IniFile.lns record comment
+
+let filter = (incl "/etc/radicale/config")
+
+let xfm = transform lns filter
index 7174959..306215e 100644 (file)
@@ -26,10 +26,10 @@ autoload xfm
 let macro_rx = /[^,# \n\t][^#\n]*[^,# \n\t]|[^,# \n\t]/
 let macro = [ key /$[A-Za-z0-9]+/ . Sep.space . store macro_rx . Util.comment_or_eol ]
 
-let config_object_param = [ key /[A-Za-z]+/ . Sep.equal . Quote.dquote
-                          . store /[^"]+/ . Quote.dquote . Sep.opt_space ]
+let config_object_param = [ key /[A-Za-z.]+/ . Sep.equal . Quote.dquote
+                          . store /[^"]+/ . Quote.dquote ]
 let config_object = [ key /action|global|input|module|parser|timezone/ . Sep.lbracket
-                    . config_object_param+ . Sep.rbracket . Util.comment_or_eol ]
+                    . config_object_param . ( Sep.space . config_object_param )* . Sep.rbracket . Util.comment_or_eol ]
 
 (* View: users
    Map :omusrmsg: and a list of users, or a single *
index e119565..12725b6 100644 (file)
@@ -79,7 +79,7 @@ let global_re   = "allow"
                 | "require"
                 | "reverse-lookup"
                 | "rootDSE"
-                | "sasl-host "
+                | "sasl-host"
                 | "sasl-realm"
                 | "sasl-secprops"
                 | "schemadn"
index 2e9c43d..3210bdd 100644 (file)
@@ -107,4 +107,5 @@ module Ssh =
     let lns = entry* . host*
 
     let xfm = transform lns (incl "/etc/ssh/ssh_config" .
-                             incl (Sys.getenv("HOME") . "/.ssh/config"))
+                             incl (Sys.getenv("HOME") . "/.ssh/config") .
+                             incl "/etc/ssh/ssh_config.d/*.conf")
index 05ffccc..ba201c2 100644 (file)
@@ -19,7 +19,7 @@ server ntp2.example.com iburst
 server ntp3.example.com presend 2
 server ntp4.example.com offline polltarget 4
 server ntp5.example.com maxdelay 2 offline
-server ntp6.example.com maxdelay 2 iburst presend 2
+server ntp6.example.com maxdelay 2 iburst presend 2 xleave offset 1e-4
 server ntp7.example.com iburst presend 2 offline prefer trust require
 server ntp8.example.com minsamples 8 maxsamples 16 version 3
 peer ntpc1.example.com
@@ -44,7 +44,7 @@ manual
 noclientlog
 logchange 0.5
 logdir /var/log/chrony
-log rtc measurements
+log rtc measurements rawmeasurements statistics tracking refclocks tempcomp
 leapsectz right/UTC
 broadcast 10 192.168.1.255
 broadcast 10 192.168.100.255 123
@@ -53,6 +53,7 @@ mailonchange root@localhost 0.5
 maxchange 1000 1 2
 maxdistance 1.0
 maxdrift 100
+hwtimestamp eth0 minpoll -2 txcomp 300e-9 rxcomp 645e-9 nocrossts
 initstepslew 30 foo.bar.com
 initstepslew 30 foo.bar.com baz.quz.com
 ratelimit interval 4 burst 16 leak 2
@@ -62,6 +63,7 @@ refclock PPS /dev/pps0 dpoll 2 poll 3 lock SHM0 rate 5 minsamples 8
 smoothtime 400 0.001 leaponly
 tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0
 tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
+ntpsigndsocket /var/lib/samba/ntp_signd
 "
 
   test Chrony.lns get exampleconf =
@@ -93,6 +95,8 @@ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
     { "maxdelay" = "2" }
     { "iburst" }
     { "presend" = "2" }
+    { "xleave" }
+    { "offset" = "1e-4" }
   }
   { "server" = "ntp7.example.com"
     { "iburst" }
@@ -147,6 +151,11 @@ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
   { "log"
     { "rtc" }
     { "measurements" }
+    { "rawmeasurements" }
+    { "statistics" }
+    { "tracking" }
+    { "refclocks" }
+    { "tempcomp" }
   }
   { "leapsectz" = "right/UTC" }
   { "broadcast"
@@ -173,6 +182,13 @@ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
   }
   { "maxdistance" = "1.0" }
   { "maxdrift" = "100" }
+  { "hwtimestamp"
+    { "interface" = "eth0" }
+    { "minpoll" = "-2" }
+    { "txcomp" = "300e-9" }
+    { "rxcomp" = "645e-9" }
+    { "nocrossts" }
+  }
   { "initstepslew"
     { "threshold" = "30" }
     { "address" = "foo.bar.com" }
@@ -223,6 +239,7 @@ tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
     { "interval" = "30" }
     { "pointfile" = "/etc/chrony.tempcomp" }
   }
+  { "ntpsigndsocket" = "/var/lib/samba/ntp_signd" }
 
 
 (* Local Variables: *)
index e17a659..f746543 100644 (file)
@@ -92,6 +92,10 @@ module Test_krb5 =
                         }
                 }
        }
+    1TS.ORG = {
+        kdc = kerberos.1ts.org
+        admin_server = kerberos.1ts.org
+    }
         stanford.edu = {
                 kdc = krb5auth1.stanford.edu
                 kdc = krb5auth2.stanford.edu
@@ -367,6 +371,10 @@ test Krb5.lns get fermi_str =
         }
       }
     }
+    { "realm" = "1TS.ORG"
+      { "kdc" = "kerberos.1ts.org" }
+      { "admin_server" = "kerberos.1ts.org" }
+    }
     { "realm" = "stanford.edu"
       { "kdc" = "krb5auth1.stanford.edu" }
       { "kdc" = "krb5auth2.stanford.edu" }
@@ -1020,3 +1028,12 @@ default_ccache_name = KEYRING:persistent:%{uid}\n" =
   { "libdefaults"
     {  }
     { "default_ccache_name" = "KEYRING:persistent:%{uid}" } }
+
+(* Include(dir) test *)
+let include_test = "include /etc/krb5.other_conf.d/other.conf
+includedir /etc/krb5.conf.d/
+"
+
+test Krb5.lns get include_test =
+  { "include" = "/etc/krb5.other_conf.d/other.conf" }
+  { "includedir" = "/etc/krb5.conf.d/" }
index d326830..da33a4d 100644 (file)
@@ -16,6 +16,7 @@ user2@virtual-alias.domain
 root    robert.oot@domain.com
 @example.net  root,postmaster
 postmaster  mtaadmin+root=mta1
+some_user  localuser
 "
 
 (* Test: Postfix_Virtual.lns *)
@@ -44,3 +45,6 @@ test Postfix_Virtual.lns get conf =
   { "pattern" = "postmaster"
     { "destination" = "mtaadmin+root=mta1" }
   }
+  { "pattern" = "some_user"
+    { "destination" = "localuser" }
+  }
diff --git a/lenses/tests/test_radicale.aug b/lenses/tests/test_radicale.aug
new file mode 100644 (file)
index 0000000..83beb70
--- /dev/null
@@ -0,0 +1,77 @@
+module Test_radicale =
+
+   let conf = "
+[server]
+
+[encoding]
+
+[well-known]
+
+[auth]
+
+[git]
+
+[rights]
+
+[storage]
+
+[logging]
+
+[headers]
+
+"
+
+   test Radicale.lns get conf =
+      {}
+      { "server"
+         {} }
+      { "encoding"
+         {} }
+      { "well-known"
+         {} }
+      { "auth"
+         {} }
+      { "git"
+         {} }
+      { "rights"
+         {} }
+      { "storage"
+         {} }
+      { "logging"
+         {} }
+      { "headers"
+         {} }
+
+    test Radicale.lns put conf after
+       set "server/hosts" "127.0.0.1:5232, [::1]:5232";
+       set "server/base_prefix" "/radicale/";
+       set "well-known/caldav" "/radicale/%(user)s/caldav/";
+       set "well-known/cardav" "/radicale/%(user)s/carddav/";
+       set "auth/type" "remote_user";
+       set "rights/type" "owner_only"
+    = "
+[server]
+
+hosts=127.0.0.1:5232, [::1]:5232
+base_prefix=/radicale/
+[encoding]
+
+[well-known]
+
+caldav=/radicale/%(user)s/caldav/
+cardav=/radicale/%(user)s/carddav/
+[auth]
+
+type=remote_user
+[git]
+
+[rights]
+
+type=owner_only
+[storage]
+
+[logging]
+
+[headers]
+
+"
index 27c7cea..0a74ea2 100644 (file)
@@ -10,7 +10,7 @@ let conf = "# rsyslog v5 configuration file
 
 $ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
 $ModLoad imklog   # provides kernel logging support (previously done by rklogd)
-module(load=\"immark\") #provides --MARK-- message capability
+module(load=\"immark\" markmessageperiod=\"60\" fakeoption=\"bar\") #provides --MARK-- message capability
 
 timezone(id=\"CET\" offset=\"+01:00\")
 
@@ -42,6 +42,8 @@ test Rsyslog.lns get conf =
   }
   { "module"
     { "load" = "immark" }
+    { "markmessageperiod" = "60" }
+    { "fakeoption" = "bar" }
     { "#comment" = "provides --MARK-- message capability" }
   }
   {  }
@@ -172,3 +174,18 @@ test Rsyslog.lns get ":msg,!contains,\"garbage\" ~\n" =
     { "value" = "garbage" }
     { "action"
       { "discard" } } }
+
+test Rsyslog.lns put "" after
+  set "/module[1]/load" "imuxsock"
+  = "module(load=\"imuxsock\")\n"
+
+test Rsyslog.lns put "" after
+  set "/module[1]/load" "imuxsock" ;
+  set "/module[1]/SysSock.RateLimit.Interval" "0"
+  = "module(load=\"imuxsock\" SysSock.RateLimit.Interval=\"0\")\n"
+
+test Rsyslog.lns put "" after
+  set "/module[1]/load" "imuxsock" ;
+  set "/module[1]/SysSock.RateLimit.Interval" "0" ;
+  set "/module[1]/SysSock.RateLimit.Burst" "1"
+  = "module(load=\"imuxsock\" SysSock.RateLimit.Interval=\"0\" SysSock.RateLimit.Burst=\"1\")\n"
index cc34856..901d6a7 100644 (file)
@@ -172,6 +172,34 @@ Tree for <complex_arg> *)
         { "argument" = "user.name=\"John Smith\" security.SMACK64=screen" }
     }
 
+  (* Variable: valid_short_args
+A short argument value example. *)
+  let valid_short_args = "h /var/log/journal - - - - C\nh /var/log/journal - - - - +C\n"
+
+  (* Variable: valid_short_args_tree
+Tree for <valid_short_args> *)
+  let valid_short_args_tree =
+    {
+        "1"
+        { "type" = "h" }
+        { "path" = "/var/log/journal" }
+        { "mode" = "-" }
+        { "uid" = "-" }
+        { "gid" = "-" }
+        { "age" = "-" }
+        { "argument" = "C" }
+    }
+    {
+        "2"
+        { "type" = "h" }
+        { "path" = "/var/log/journal" }
+        { "mode" = "-" }
+        { "uid" = "-" }
+        { "gid" = "-" }
+        { "age" = "-" }
+        { "argument" = "+C" }
+    }
+
   (* Variable: valid_age
 Example with a complex age. *)
   let valid_age = "v /var/tmp/js 4221 johnsmith - ~10d12h\n"
@@ -277,6 +305,20 @@ Tree for <valid_base> *)
         { "argument" = "foo" }
     }
 
+  (* Variable: mode3
+Mode field example with only three digits *)
+  let mode3 = "c+! /tmp/foo 755\n"
+
+  (* Variable: mode3_tree
+Tree for <mode3> *)
+  let mode3_tree =
+    {
+        "1"
+        { "type" = "c+!" }
+        { "path" = "/tmp/foo" }
+        { "mode" = "755" }
+    }
+
 (************************************************************************
  * Group:                 INVALID EXAMPLES
  *************************************************************************)
@@ -291,7 +333,7 @@ Invalid example that contain invalid age  *)
 
   (* Variable: invalid_type
 Invalid example that contain invalid type (bad letter) *)
-  let invalid_type = "q /var/tmp/js 0000 jonhsmith 60 1s foo\n"
+  let invalid_type = "e /var/tmp/js 0000 jonhsmith 60 1s foo\n"
 
   (* Variable: invalid_type_num
  Invalid example that contain invalid type (numeric) *)
@@ -327,6 +369,8 @@ Invalid example that contain invalid mode (letter) *)
 
   test Tmpfiles.lns get complex_arg = complex_arg_tree
 
+  test Tmpfiles.lns get valid_short_args = valid_short_args_tree
+
   test Tmpfiles.lns get valid_second = valid_second_tree
 
   test Tmpfiles.lns get valid_days = valid_days_tree
@@ -339,6 +383,8 @@ Invalid example that contain invalid mode (letter) *)
 
   test Tmpfiles.lns get valid_base = valid_base_tree
 
+  test Tmpfiles.lns get mode3 = mode3_tree
+
 
 (* failure cases *)
 
index f78176a..7156083 100644 (file)
@@ -826,3 +826,80 @@ test Xml.lns get "<a password=\"my\!pass\" />" =
 
 test Xml.lns put ""
 after set "/a" "#empty" = "<a/>\n"
+
+(* Issue #142 *)
+test Xml.entity_def get
+  "<!ENTITY open-hatch SYSTEM \"http://examplecom/OpenHatch.xml\">" =
+  { "!ENTITY" = "open-hatch"
+    { "SYSTEM"
+      { "#systemliteral" = "http://examplecom/OpenHatch.xml" }
+    } }
+
+test Xml.entity_def get
+  "<!ENTITY open-hatch PUBLIC \"-//Textuality//TEXT Standard open-hatch boilerplate//EN\" \"http://www.textuality.com/boilerplate/OpenHatch.xml\">" =
+  { "!ENTITY" = "open-hatch"
+    { "PUBLIC"
+      { "#pubidliteral" =
+          "-//Textuality//TEXT Standard open-hatch boilerplate//EN" }
+      { "#systemliteral" =
+          "http://www.textuality.com/boilerplate/OpenHatch.xml" } } }
+
+let dt_with_entities =
+"<!DOCTYPE server-xml [
+  <!ENTITY sys-ent SYSTEM \"sys-file.xml\">
+  <!ENTITY pub-ent PUBLIC \"-//something public//TEXT\"
+                          \"pub-file.xml\">
+ ]>"
+
+test Xml.doctype get dt_with_entities =
+  { "!DOCTYPE" = "server-xml"
+    { "!ENTITY" = "sys-ent"
+      { "SYSTEM"
+        { "#systemliteral" = "sys-file.xml" }
+      }
+    }
+    { "!ENTITY" = "pub-ent"
+      { "PUBLIC"
+        { "#pubidliteral" = "-//something public//TEXT" }
+        { "#systemliteral" = "pub-file.xml" }
+      }
+    }
+  }
+
+test Xml.doctype put dt_with_entities after
+    rm "/\!DOCTYPE/\!ENTITY[2]";
+    set "/\!DOCTYPE/\!ENTITY[. = \"sys-ent\"]/SYSTEM/#systemliteral"
+        "other-file.xml"
+  =
+"<!DOCTYPE server-xml [
+  <!ENTITY sys-ent SYSTEM \"other-file.xml\">
+  ]>"
+
+test Xml.lns get (dt_with_entities . "<body></body>") =
+  { "!DOCTYPE" = "server-xml"
+    { "!ENTITY" = "sys-ent"
+      { "SYSTEM"
+        { "#systemliteral" = "sys-file.xml" }
+      }
+    }
+    { "!ENTITY" = "pub-ent"
+      { "PUBLIC"
+        { "#pubidliteral" = "-//something public//TEXT" }
+        { "#systemliteral" = "pub-file.xml" }
+      }
+    }
+  }
+  { "body" }
+
+test Xml.lns put "<?xml version=\"1.0\"?>
+<body>
+</body>"
+    after
+    insa "!DOCTYPE" "#declaration";
+    set "\\!DOCTYPE" "Server";
+    set "\\!DOCTYPE/\\!ENTITY" "resourcesFile";
+    set "\\!DOCTYPE/\\!ENTITY/SYSTEM/#systemliteral" "data.xml"
+  =
+"<?xml version=\"1.0\"?><!DOCTYPE Server[
+<!ENTITY resourcesFile SYSTEM \"data.xml\">]>
+<body>\n</body>"
index 7d82f7c..f426910 100644 (file)
@@ -53,11 +53,11 @@ One letter. Some of them can have a "+" and all can have a "!".
 
 Not all letters are valid.
 *)
-  let type     = /([fFwdDvpLcbCxXrRzZtThHaAm]|[AabcLp]\+)!?/
+  let type     = /([fFwdDvqQpLcbCxXrRzZtThHaAm]|[AabcLp]\+)!?/
 
   (* View: mode
-"-", or 4 bytes. Optionally starts with a "~". *)
-  let mode     = /(-|~?[0-7]{4})/
+"-", or 3-4 bytes. Optionally starts with a "~". *)
+  let mode     = /(-|~?[0-7]{3,4})/
 
   (* View: age
 "-", or one of the formats seen in the manpage: 10d, 5seconds, 1y5days.
@@ -66,7 +66,7 @@ optionally starts with a "~'. *)
 
   (* View: argument
 The last field. It can contain spaces. *)
-  let argument = /([^# \t\n][^#\n]+)?[^# \t\n]/
+  let argument = /([^# \t\n][^#\n]*[^# \t\n]|[^# \t\n])/
 
   (* View: field
 Applies to the other fields: path, gid and uid fields *)
index 60649dc..342b13b 100644 (file)
@@ -78,7 +78,13 @@ let att_def       = counter "att_id" .
 
 let att_list_def = decl_def /!ATTLIST/ att_def
 
-let entity_def    = decl_def /!ENTITY/ ([sep_spc . label "#decl" . sto_dquote ])
+let entity_def   =
+  let literal (lbl:string) = [ sep_spc . label lbl . sto_dquote ] in
+  decl_def /!ENTITY/
+    ( literal "#decl"
+    | [ sep_spc . key /SYSTEM/ . literal "#systemliteral" ]
+    | [ sep_spc . key /PUBLIC/ . literal "#pubidliteral"
+                               . literal "#systemliteral" ] )
 
 let decl_def_item = elem_def | entity_def | att_list_def | notation_def
 
index 035d81a..9c9019f 100644 (file)
@@ -53,6 +53,9 @@ let lns    = (empty | comment)* . record*
       . (incl "/etc/yum/yum-cron*.conf") 
       . (incl "/etc/yum/pluginconf.d/*")
       . (excl "/etc/yum/pluginconf.d/versionlock.list")
+      . (incl "/etc/dnf/dnf.conf")
+      . (incl "/etc/dnf/automatic.conf")
+      . (incl "/etc/dnf/plugins/*.conf")
       . Util.stdexcl
 
   let xfm = transform lns filter
index 5616796..fe5f593 100644 (file)
@@ -23,7 +23,7 @@ libaugeas_la_SOURCES = augeas.h augeas.c augrun.c pathx.c \
        memory.h memory.c ref.h ref.c \
     syntax.c syntax.h parser.y builtin.c lens.c lens.h regexp.c regexp.h \
        transform.h transform.c ast.c get.c put.c list.h \
-    info.c info.h errcode.c errcode.h jmt.h jmt.c
+    info.c info.h errcode.c errcode.h jmt.h jmt.c xml.c
 
 if USE_VERSION_SCRIPT
   AUGEAS_VERSION_SCRIPT = $(VERSION_SCRIPT_FLAGS)$(srcdir)/augeas_sym.version
index b812d96..f823a60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * augeas.c: the core data structure for storing key/value pairs
  *
- * Copyright (C) 2007-2016 David Lutterkort
+ * Copyright (C) 2007-2017 David Lutterkort
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -33,7 +33,6 @@
 #include <string.h>
 #include <stdarg.h>
 #include <locale.h>
-#include <libxml/tree.h>
 
 /* Some popular labels that we use in /augeas */
 static const char *const s_augeas = "augeas";
@@ -47,8 +46,6 @@ static const char *const s_lens   = "lens";
 static const char *const s_excl   = "excl";
 static const char *const s_incl   = "incl";
 
-#define TREE_HIDDEN(tree) ((tree)->label == NULL)
-
 #define AUGEAS_META_PATHX_FUNC AUGEAS_META_TREE "/version/pathx/functions"
 
 static const char *const static_nodes[][2] = {
@@ -1718,147 +1715,6 @@ int dump_tree(FILE *out, struct tree *tree) {
     return result;
 }
 
-static int to_xml_span(xmlNodePtr elem, const char *pfor, int start, int end) {
-    int r;
-    char *buf;
-    xmlAttrPtr prop;
-    xmlNodePtr span_elem;
-
-    span_elem = xmlNewChild(elem, NULL, BAD_CAST "span", NULL);
-    if (span_elem == NULL)
-        return -1;
-
-    prop = xmlSetProp(span_elem, BAD_CAST "for", BAD_CAST pfor);
-    if (prop == NULL)
-        return -1;
-
-    /* Format and set the start property */
-    r = xasprintf(&buf, "%d", start);
-    if (r < 0)
-        return -1;
-
-    prop = xmlSetProp(span_elem, BAD_CAST "start", BAD_CAST buf);
-    FREE(buf);
-    if (prop == NULL)
-        return -1;
-
-    /* Format and set the end property */
-    r = xasprintf(&buf, "%d", end);
-    if (r < 0)
-        return -1;
-
-    prop = xmlSetProp(span_elem, BAD_CAST "end", BAD_CAST buf);
-    FREE(buf);
-    if (prop == NULL)
-        return -1;
-
-    return 0;
-}
-
-static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
-                      const char *pathin) {
-    xmlNodePtr value;
-    xmlAttrPtr prop;
-    int r;
-
-    prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
-    if (prop == NULL)
-        goto error;
-
-    if (tree->span) {
-        struct span *span = tree->span;
-
-        prop = xmlSetProp(elem, BAD_CAST "file",
-                          BAD_CAST span->filename->str);
-        if (prop == NULL)
-            goto error;
-
-        r = to_xml_span(elem, "label", span->label_start, span->label_end);
-        if (r < 0)
-            goto error;
-
-        r = to_xml_span(elem, "value", span->value_start, span->value_end);
-        if (r < 0)
-            goto error;
-
-        r = to_xml_span(elem, "node", span->span_start, span->span_end);
-        if (r < 0)
-            goto error;
-    }
-
-    if (pathin != NULL) {
-        prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
-        if (prop == NULL)
-            goto error;
-    }
-    if (tree->value != NULL) {
-        value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
-                                BAD_CAST tree->value);
-        if (value == NULL)
-            goto error;
-    }
-    return 0;
- error:
-    return -1;
-}
-
-static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
-                      const char *pathin) {
-    int r;
-    xmlNodePtr elem;
-
-    elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
-    if (elem == NULL)
-        goto error;
-    r = to_xml_one(elem, start, pathin);
-    if (r < 0)
-        goto error;
-
-    list_for_each(tree, start->children) {
-        if (TREE_HIDDEN(tree))
-            continue;
-        r = to_xml_rec(elem, tree, NULL);
-        if (r < 0)
-            goto error;
-    }
-
-    return 0;
- error:
-    return -1;
-}
-
-static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
-    char *path = NULL;
-    struct tree *tree;
-    xmlAttrPtr expr;
-    int r;
-
-    *xml = xmlNewNode(NULL, BAD_CAST "augeas");
-    if (*xml == NULL)
-        goto error;
-    expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
-    if (expr == NULL)
-        goto error;
-
-    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
-        if (TREE_HIDDEN(tree))
-            continue;
-        path = path_of_tree(tree);
-        if (path == NULL)
-            goto error;
-        r = to_xml_rec(*xml, tree, path);
-        if (r < 0)
-            goto error;
-        FREE(path);
-    }
-    return 0;
- error:
-    free(path);
-    xmlFree(*xml);
-    *xml = NULL;
-    return -1;
-}
-
 int aug_text_store(augeas *aug, const char *lens, const char *node,
                    const char *path) {
 
@@ -1924,33 +1780,6 @@ int aug_text_retrieve(struct augeas *aug, const char *lens,
     return -1;
 }
 
-int aug_to_xml(const struct augeas *aug, const char *pathin,
-               xmlNode **xmldoc, unsigned int flags) {
-    struct pathx *p = NULL;
-    int result = -1;
-
-    api_entry(aug);
-
-    ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
-    ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
-
-    *xmldoc = NULL;
-
-    if (pathin == NULL || strlen(pathin) == 0 || strcmp(pathin, "/") == 0) {
-        pathin = "/*";
-    }
-
-    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
-    ERR_BAIL(aug);
-    result = tree_to_xml(p, xmldoc, pathin);
-    ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
-error:
-    free_pathx(p);
-    api_exit(aug);
-
-    return result;
-}
-
 int aug_transform(struct augeas *aug, const char *lens,
                   const char *file, int excl) {
     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
@@ -2086,6 +1915,41 @@ int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
     return result;
 }
 
+int aug_source(const augeas *aug, const char *path, char **file_path) {
+    int result = -1, r;
+    struct pathx *p = NULL;
+    struct tree *match;
+
+    api_entry(aug);
+
+    ARG_CHECK(file_path == NULL, aug,
+              "aug_source_file: FILE_PATH must not be NULL");
+    *file_path = NULL;
+
+    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
+    ERR_BAIL(aug);
+
+    r = pathx_find_one(p, &match);
+    ERR_BAIL(aug);
+    ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
+              r, path);
+    ERR_THROW(r == 0, aug, AUG_ENOMATCH, "There is no node matching %s",
+              path);
+    while (!(ROOT_P(match) || match->file))
+        match = match->parent;
+
+    if (match->file) {
+        *file_path = path_of_tree(match);
+        ERR_NOMEM(file_path == NULL, aug);
+    }
+
+    result = 0;
+ error:
+    free_pathx(p);
+    api_exit(aug);
+    return result;
+}
+
 void aug_close(struct augeas *aug) {
     if (aug == NULL)
         return;
index 31b7cd3..29789cf 100644 (file)
@@ -396,6 +396,19 @@ int aug_escape_name(augeas *aug, const char *in, char **out);
  */
 int aug_print(const augeas *aug, FILE *out, const char *path);
 
+/* Function: aug_source
+ *
+ * For the node matching PATH, return the path to the node representing the
+ * file to which PATH belongs. If PATH belongs to a file, *FILE_PATH will
+ * contain the path to the toplevel node of that file underneath /files. If
+ * it does not, *FILE_PATH will be NULL.
+ *
+ * Returns:
+ * 0 on success, or a negative value on failure. It is an error if PATH
+ * matches more than one node.
+ */
+int aug_source(const augeas *aug, const char *path, char **file_path);
+
 /* Function: aug_to_xml
  *
  * Turn the Augeas tree(s) matching PATH into an XML tree XMLDOC. The
index 7417597..86be54c 100644 (file)
@@ -75,3 +75,8 @@ AUGEAS_0.21.0 {
     global:
       aug_load_file;
 } AUGEAS_0.20.0;
+
+AUGEAS_0.22.0 {
+    global:
+      aug_source;
+} AUGEAS_0.21.0;
index 15b1984..5ddc5ea 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <ctype.h>
 #include <libxml/tree.h>
+#include <argz.h>
 
 /*
  * Command handling infrastructure
@@ -935,6 +936,63 @@ static const struct command_def cmd_print_def = {
     .help = "Print entries in the tree.  If PATH is given, printing starts there,\n otherwise the whole tree is printed"
 };
 
+static void cmd_source(struct command *cmd) {
+    const char *path = arg_value(cmd, "path");
+    char *file_path = NULL;
+
+    aug_source(cmd->aug, path, &file_path);
+    ERR_RET(cmd);
+    if (file_path != NULL) {
+        fprintf(cmd->out, "%s\n", file_path);
+    }
+    free(file_path);
+}
+
+static const struct command_opt_def cmd_source_opts[] = {
+    { .type = CMD_PATH, .name = "path", .optional = false,
+      .help = "path to a single node" },
+    CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_source_def = {
+    .name = "source",
+    .opts = cmd_source_opts,
+    .handler = cmd_source,
+    .synopsis = "print the file to which a node belongs",
+    .help = "Print the file to which the node for PATH belongs. PATH must match\n a single node coming from some file. In particular, that means\n it must be underneath /files."
+};
+
+static void cmd_context(struct command *cmd) {
+    const char *path = arg_value(cmd, "path");
+
+    if (path == NULL) {
+        aug_get(cmd->aug, "/augeas/context", &path);
+        ERR_RET(cmd);
+        if (path == NULL) {
+            fprintf(cmd->out, "/\n");
+        } else {
+            fprintf(cmd->out, "%s\n", path);
+        }
+    } else {
+        aug_set(cmd->aug, "/augeas/context", path);
+        ERR_RET(cmd);
+    }
+}
+
+static const struct command_opt_def cmd_context_opts[] = {
+    { .type = CMD_PATH, .name = "path", .optional = true,
+      .help = "new context for relative paths" },
+    CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_context_def = {
+    .name = "context",
+    .opts = cmd_context_opts,
+    .handler = cmd_context,
+    .synopsis = "change how relative paths are interpreted",
+    .help = "Relative paths are interpreted relative to a context path which\n is stored in /augeas/context.\n\n When no PATH is given, this command prints the current context path\n and is equivalent to 'get /augeas/context'\n\n When PATH is given, this command changes that context, and has a\n similar effect to 'cd' in a shell and and is the same as running\n the command 'set /augeas/context PATH'."
+};
+
 static void cmd_dump_xml(struct command *cmd) {
     const char *path = arg_value(cmd, "path");
     xmlNodePtr xmldoc;
@@ -1090,6 +1148,63 @@ static const struct command_def cmd_load_def = {
     "is an  error if one file\n can be processed by multiple transforms."
 };
 
+static void cmd_info(struct command *cmd) {
+    const char *v;
+    int n;
+
+    aug_get(cmd->aug, "/augeas/version", &v);
+    ERR_RET(cmd);
+    if (v != NULL) {
+        fprintf(cmd->out, "version = %s\n", v);
+    }
+
+    aug_get(cmd->aug, "/augeas/root", &v);
+    ERR_RET(cmd);
+    if (v != NULL) {
+        fprintf(cmd->out, "root = %s\n", v);
+    }
+
+    fprintf(cmd->out, "loadpath = ");
+    for (char *entry = cmd->aug->modpathz;
+         entry != NULL;
+         entry = argz_next(cmd->aug->modpathz, cmd->aug->nmodpath, entry)) {
+        if (entry != cmd->aug->modpathz) {
+            fprintf(cmd->out, ":");
+        }
+        fprintf(cmd->out, "%s", entry);
+    }
+    fprintf(cmd->out, "\n");
+
+    aug_get(cmd->aug, "/augeas/context", &v);
+    ERR_RET(cmd);
+    if (v == NULL) {
+        v = "/";
+    }
+    fprintf(cmd->out, "context = %s\n", v);
+
+    n = aug_match(cmd->aug, "/augeas/files//path", NULL);
+    fprintf(cmd->out, "num_files = %d\n", n);
+}
+
+static const struct command_opt_def cmd_info_opts[] = {
+    CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_info_def = {
+    .name = "info",
+    .opts = cmd_info_opts,
+    .handler = cmd_info,
+    .synopsis = "print runtime information",
+    .help = "Print information about Augeas. The output contains:\n"
+            "    version   : the version number from /augeas/version\n"
+            "    root      : what Augeas considers the filesystem root\n"
+            "                from /augeas/root\n"
+            "    loadpath  : the paths from which Augeas loads modules\n"
+            "    context   : the context path (see context command)\n"
+            "    num_files : the number of files currently loaded (based on\n"
+            "                the number of /augeas/files//path nodes)"
+};
+
 static void cmd_ins(struct command *cmd) {
     const char *label = arg_value(cmd, "label");
     const char *where = arg_value(cmd, "where");
@@ -1316,14 +1431,25 @@ static const struct command_def cmd_errors_def = {
 static const struct command_grp_def cmd_grp_admin_def = {
     .name = "Admin",
     .commands = {
-        &cmd_help_def,
+        &cmd_context_def,
         &cmd_load_def,
-        &cmd_quit_def,
-        &cmd_retrieve_def,
         &cmd_save_def,
-        &cmd_store_def,
         &cmd_transform_def,
         &cmd_load_file_def,
+        &cmd_retrieve_def,
+        &cmd_store_def,
+        &cmd_quit_def,
+        &cmd_def_last
+    }
+};
+
+static const struct command_grp_def cmd_grp_info_def = {
+    .name = "Informational",
+    .commands = {
+        &cmd_errors_def,
+        &cmd_info_def,
+        &cmd_help_def,
+        &cmd_source_def,
         &cmd_def_last
     }
 };
@@ -1337,7 +1463,6 @@ static const struct command_grp_def cmd_grp_read_def = {
         &cmd_ls_def,
         &cmd_match_def,
         &cmd_print_def,
-        &cmd_errors_def,
         &cmd_span_def,
         &cmd_def_last
     }
@@ -1374,6 +1499,7 @@ static const struct command_grp_def cmd_grp_pathx_def = {
 
 static const struct command_grp_def const *cmd_groups[] = {
     &cmd_grp_admin_def,
+    &cmd_grp_info_def,
     &cmd_grp_read_def,
     &cmd_grp_write_def,
     &cmd_grp_pathx_def,
index b6ab4a7..17300c4 100644 (file)
@@ -65,8 +65,10 @@ char *history_file = NULL;
  * General utilities
  */
 
-/* Not static, since prototype is in internal.h */
-int xasprintf(char **strp, const char *format, ...) {
+/* Private copy of xasprintf from internal to avoid Multiple definition in
+ * static builds.
+ */
+static int _xasprintf(char **strp, const char *format, ...) {
   va_list args;
   int result;
 
@@ -180,7 +182,9 @@ static char *readline_command_generator(const char *text, int state) {
         "get", "label", "ins", "load", "ls", "match",
         "mv", "cp", "rename", "print", "dump-xml", "rm", "save", "set", "setm",
         "clearm", "span", "store", "retrieve", "transform", "load-file",
-        "help", "touch", "insert", "move", "copy", "errors", NULL };
+        "help", "touch", "insert", "move", "copy", "errors", "source", "context",
+        "info",
+        NULL };
 
     static int current = 0;
     const char *name;
@@ -268,13 +272,13 @@ static void readline_init(void) {
     if (home_dir == NULL)
         goto done;
 
-    if (xasprintf(&history_dir, "%s/.augeas", home_dir) < 0)
+    if (_xasprintf(&history_dir, "%s/.augeas", home_dir) < 0)
         goto done;
 
     if (mkdir(history_dir, 0755) < 0 && errno != EEXIST)
         goto done;
 
-    if (xasprintf(&history_file, "%s/history", history_dir) < 0)
+    if (_xasprintf(&history_file, "%s/history", history_dir) < 0)
         goto done;
 
     stifle_history(500);
@@ -639,7 +643,7 @@ static void add_transforms(char *ts, size_t tslen) {
     bool added_transform = false;
 
     while ((t = argz_next(ts, tslen, t))) {
-        r = xasprintf(&command, "transform %s", t);
+        r = _xasprintf(&command, "transform %s", t);
         if (r < 0)
             fprintf(stderr, "error: Failed to add transform %s: could not allocate memory\n", t);
 
@@ -664,7 +668,7 @@ static void load_files(char *ts, size_t tslen) {
     char *t = NULL;
 
     while ((t = argz_next(ts, tslen, t))) {
-        r = xasprintf(&command, "load-file %s", t);
+        r = _xasprintf(&command, "load-file %s", t);
         if (r < 0)
             fprintf(stderr, "error: Failed to load file %s: could not allocate memory\n", t);
 
index 130b423..e9dbd68 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * internal.h: Useful definitions
  *
- * Copyright (C) 2007-2016 David Lutterkort
+ * Copyright (C) 2007-2017 David Lutterkort
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -380,8 +380,10 @@ void api_exit(const struct augeas *aug);
  * file should have a need to mark nodes as dirty)
  *
  * The FILE flag is set for entries underneath /augeas/files that hold the
- * metadata for a file. It is only set by ADD_FILE_INFO and can not be set
- * by the user.
+ * metadata for a file by ADD_FILE_INFO. The FILE flag is set for entries
+ * underneath /files for the toplevel node corresponding to a file by
+ * TREE_FREPLACE and is used by AUG_SOURCE to find the file to which a node
+ * belongs.
  */
 struct tree {
     struct tree *next;
@@ -405,6 +407,8 @@ struct pathx;
 
 #define ROOT_P(t) ((t) != NULL && (t)->parent == (t)->parent->parent)
 
+#define TREE_HIDDEN(tree) ((tree)->label == NULL)
+
 /* Function: make_tree
  * Allocate a new tree node with the given LABEL, VALUE, and CHILDREN,
  * which are not copied. The new tree is marked as dirty
index 1b9ec86..8632ce1 100644 (file)
@@ -1056,6 +1056,10 @@ void lens_release(struct lens *lens) {
         }
     }
 
+    if (lens->tag == L_REC && !lens->rec_internal) {
+        lens_release(lens->body);
+    }
+
     jmt_free(lens->jmt);
     lens->jmt = NULL;
 }
index 110b951..d45b646 100644 (file)
@@ -2002,9 +2002,14 @@ int load_module_file(struct augeas *aug, const char *filename,
          */
         module = module_create(name);
     }
-    if (module != NULL)
+    if (module != NULL) {
         list_append(aug->modules, module);
-
+        list_for_each(bnd, module->bindings) {
+            if (bnd->value->tag == V_LENS) {
+                lens_release(bnd->value->lens);
+            }
+        }
+    }
     ERR_THROW(bad_module, aug, AUG_ESYNTAX, "Failed to load %s", filename);
 
     result = 0;
index 1f80134..5423ba1 100644 (file)
@@ -540,6 +540,7 @@ static void tree_freplace(struct augeas *aug, const char *fpath,
     parent = tree_fpath_cr(aug, fpath);
     ERR_RET(aug);
 
+    parent->file = true;
     tree_unlink_children(aug, parent);
     list_append(parent->children, sub);
     list_for_each(s, sub) {
diff --git a/src/xml.c b/src/xml.c
new file mode 100644 (file)
index 0000000..bd87921
--- /dev/null
+++ b/src/xml.c
@@ -0,0 +1,198 @@
+/*
+ * xml.c: the implementation of aug_to_xml and supporting functions
+ *
+ * Copyright (C) 2017 David Lutterkort
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: David Lutterkort <lutter@watzmann.net>
+ */
+
+#include <config.h>
+#include "augeas.h"
+#include "internal.h"
+#include "memory.h"
+#include "info.h"
+#include "errcode.h"
+
+#include <libxml/tree.h>
+
+static int to_xml_span(xmlNodePtr elem, const char *pfor, int start, int end) {
+    int r;
+    char *buf;
+    xmlAttrPtr prop;
+    xmlNodePtr span_elem;
+
+    span_elem = xmlNewChild(elem, NULL, BAD_CAST "span", NULL);
+    if (span_elem == NULL)
+        return -1;
+
+    prop = xmlSetProp(span_elem, BAD_CAST "for", BAD_CAST pfor);
+    if (prop == NULL)
+        return -1;
+
+    /* Format and set the start property */
+    r = xasprintf(&buf, "%d", start);
+    if (r < 0)
+        return -1;
+
+    prop = xmlSetProp(span_elem, BAD_CAST "start", BAD_CAST buf);
+    FREE(buf);
+    if (prop == NULL)
+        return -1;
+
+    /* Format and set the end property */
+    r = xasprintf(&buf, "%d", end);
+    if (r < 0)
+        return -1;
+
+    prop = xmlSetProp(span_elem, BAD_CAST "end", BAD_CAST buf);
+    FREE(buf);
+    if (prop == NULL)
+        return -1;
+
+    return 0;
+}
+
+static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
+                      const char *pathin) {
+    xmlNodePtr value;
+    xmlAttrPtr prop;
+    int r;
+
+    prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
+    if (prop == NULL)
+        goto error;
+
+    if (tree->span) {
+        struct span *span = tree->span;
+
+        prop = xmlSetProp(elem, BAD_CAST "file",
+                          BAD_CAST span->filename->str);
+        if (prop == NULL)
+            goto error;
+
+        r = to_xml_span(elem, "label", span->label_start, span->label_end);
+        if (r < 0)
+            goto error;
+
+        r = to_xml_span(elem, "value", span->value_start, span->value_end);
+        if (r < 0)
+            goto error;
+
+        r = to_xml_span(elem, "node", span->span_start, span->span_end);
+        if (r < 0)
+            goto error;
+    }
+
+    if (pathin != NULL) {
+        prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
+        if (prop == NULL)
+            goto error;
+    }
+    if (tree->value != NULL) {
+        value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
+                                BAD_CAST tree->value);
+        if (value == NULL)
+            goto error;
+    }
+    return 0;
+ error:
+    return -1;
+}
+
+static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
+                      const char *pathin) {
+    int r;
+    xmlNodePtr elem;
+
+    elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
+    if (elem == NULL)
+        goto error;
+    r = to_xml_one(elem, start, pathin);
+    if (r < 0)
+        goto error;
+
+    list_for_each(tree, start->children) {
+        if (TREE_HIDDEN(tree))
+            continue;
+        r = to_xml_rec(elem, tree, NULL);
+        if (r < 0)
+            goto error;
+    }
+
+    return 0;
+ error:
+    return -1;
+}
+
+static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
+    char *path = NULL;
+    struct tree *tree;
+    xmlAttrPtr expr;
+    int r;
+
+    *xml = xmlNewNode(NULL, BAD_CAST "augeas");
+    if (*xml == NULL)
+        goto error;
+    expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
+    if (expr == NULL)
+        goto error;
+
+    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
+        if (TREE_HIDDEN(tree))
+            continue;
+        path = path_of_tree(tree);
+        if (path == NULL)
+            goto error;
+        r = to_xml_rec(*xml, tree, path);
+        if (r < 0)
+            goto error;
+        FREE(path);
+    }
+    return 0;
+ error:
+    free(path);
+    xmlFree(*xml);
+    *xml = NULL;
+    return -1;
+}
+
+int aug_to_xml(const struct augeas *aug, const char *pathin,
+               xmlNode **xmldoc, unsigned int flags) {
+    struct pathx *p = NULL;
+    int result = -1;
+
+    api_entry(aug);
+
+    ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
+    ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
+
+    *xmldoc = NULL;
+
+    if (pathin == NULL || strlen(pathin) == 0 || strcmp(pathin, "/") == 0) {
+        pathin = "/*";
+    }
+
+    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
+    ERR_BAIL(aug);
+    result = tree_to_xml(p, xmldoc, pathin);
+    ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
+error:
+    free_pathx(p);
+    api_exit(aug);
+
+    return result;
+}
index 1a4aeee..998891c 100644 (file)
@@ -168,6 +168,7 @@ lens_tests =                        \
   lens-qpid.sh         \
   lens-quote.sh                \
   lens-rabbitmq.sh             \
+  lens-radicale.sh             \
   lens-redis.sh                \
   lens-reprepro_uploaders.sh           \
   lens-resolv.sh               \