Imported Upstream version 1.6.0 37/91137/1 upstream/1.6.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 6 Oct 2016 04:47:13 +0000 (13:47 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 6 Oct 2016 04:47:23 +0000 (13:47 +0900)
Change-Id: Ib488a1803305cd67ce55b116ebba415d68c0e787
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
36 files changed:
AUTHORS
NEWS
configure.ac
doc/naturaldocs/conf/lenses/Languages.txt
doc/naturaldocs/conf/lenses/Menu.txt
lenses/httpd.aug
lenses/nginx.aug
lenses/ntp.aug
lenses/pam.aug
lenses/pamconf.aug
lenses/postfix_passwordmap.aug [new file with mode: 0644]
lenses/rsyslog.aug
lenses/shellvars.aug
lenses/tests/test_httpd.aug
lenses/tests/test_ntp.aug
lenses/tests/test_postfix_passwordmap.aug [new file with mode: 0644]
lenses/tests/test_rsyslog.aug
lenses/tests/test_vsftpd.aug
lenses/vsftpd.aug
man/augtool.1
man/augtool.pod
src/augeas.c
src/augeas.h
src/augeas_sym.version
src/augrun.c
src/augtool.c
src/fa.c
src/internal.c
src/pathx.c
src/transform.c
src/transform.h
tests/Makefile.am
tests/test-api.c
tests/test-augtool/rec-append-record.sh
tests/test-augtool/rec-ins-record.sh
tests/test-augtool/rec-mod-field.sh

diff --git a/AUTHORS b/AUTHORS
index 99d6174..5c25c34 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -139,3 +139,7 @@ Contributions by:
   Chris Reeves                <chris.reeves@york.ac.uk>
   Gerlof Fokkema              <gerlof.fokkema@gmail.com>
   Daniel Trebbien             <dtrebbien@gmail.com>
+  Robert Moucha               <robert.moucha@gooddata.com>
+  Craig Miskell               <craig@catalyst.net.nz>
+  Anton Baranov               <abaranov@linuxfoundation.org>
+  Josef Reidinger             <jreidinger@suse.cz>
diff --git a/NEWS b/NEWS
index 7fdf6cd..e4dd082 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,30 @@
-1.5.0 - 2015-05-11
+1.6.0 - 2016-08-05
+  - General changes/additions
+    * augtool: add --load-file option, and corresponding load-file command
+      to load individual files based on the autoload information in lenses
+    * path expressions: numbers in path expressions are now 64 bit integers
+      rather than whatever the C compiler decided 'int' would be
+  - API changes
+    * add aug_load_file to load individual files, bug #135
+  - Lens changes/additions
+    * Httpd: follow line continuations in comments
+    * Nginx: look for nginx.conf in /usr/local/etc, too (Omer Katz)
+    * Ntp: allow 'pool' (Craig Miskell) (Issue #378);
+           fix restrict to allow also -4 and also fix
+           save/store ability (Josef Reidinger) (Issue #386)
+    * Pam: use spaces instead of tabs as the separator in new entries
+           (Loren Gordon) (Issue #236)
+    * Postfix_Passwordmap: New lens to parse Postfix password maps
+           (Anton Baranov) (Issue #380)
+    * Rsyslog: Support for rsyslog RainerScript syntax
+           (Craig Miskell) (Issue #379)
+    * Shellvars: Load /etc/lbu/lbu.conf, the config for Alpine's Local
+           Backup Utility (Kaarle Ritvanen)
+           Load /etc/profile, /etc/profile.d/*, and /etc/byobu
+    * Vsftpd: Add allow_writeable_chroot boolead option
+           (Robert Moucha) (Issue #376)
+
+1.5.0 - 2016-05-11
   - General changes/additions
     * augtool: new --timing option that prints after each operation how long
       it took
index 72b6984..ce1ff70 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT(augeas, 1.5.0)
+AC_INIT(augeas, 1.6.0)
 AC_CONFIG_SRCDIR([src/augeas.c])
 AC_CONFIG_AUX_DIR([build/ac-aux])
 AM_CONFIG_HEADER([config.h])
@@ -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], [20:1:20])
-AC_SUBST([LIBFA_VERSION_INFO], [5:2:4])
+AC_SUBST([LIBAUGEAS_VERSION_INFO], [21:0:21])
+AC_SUBST([LIBFA_VERSION_INFO], [5:3:4])
 
 AC_GNU_SOURCE
 
index 499f12a..47a9622 100644 (file)
@@ -117,7 +117,7 @@ Language: Augeas
 
    Extension: aug
    Block Comment: (* *)
-   Augeas Variable Prototype Enders: \n let test module filter
    Augeas Test Prototype Enders: \n let test module filter
    Augeas Lens Prototype Enders: \n let test module filter
+   Augeas Variable Prototype Enders: \n let test module filter
    Perl Package: NaturalDocs::Languages::Augeas
index 78820a2..b9410c7 100644 (file)
@@ -145,6 +145,7 @@ Group: Specific Modules  {
    File: Passwd  (passwd.aug)
    File: Pbuilder  (pbuilder.aug)
    File: Pg_Hba  (pg_hba.aug)
+   File: Postfix_Passwordmap  (postfix_passwordmap.aug)
    File: Postfix_Transport  (postfix_transport.aug)
    File: Postfix_Virtual  (postfix_virtual.aug)
    File: Postgresql  (postgresql.aug)
@@ -263,6 +264,7 @@ Group: Tests and Examples  {
    File: Test_OpenShift_Config  (tests/test_openshift_config.aug)
    File: Test_OpenShift_Http  (tests/test_openshift_http.aug)
    File: Test_OpenShift_Quickstarts  (tests/test_openshift_quickstarts.aug)
+   File: Test_Postfix_Passwordmap  (tests/test_postfix_passwordmap.aug)
    File: Test_Postfix_Transport  (tests/test_postfix_transport.aug)
    File: Test_Postfix_Virtual  (tests/test_postfix_virtual.aug)
    File: Test_Postgresql  (tests/test_postgresql.aug)
index 7a5129b..2729f4b 100644 (file)
@@ -52,11 +52,14 @@ let sep_eq              = del /[ \t]*=[ \t]*/ "="
 let nmtoken             = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
 let word                = /[a-z][a-z0-9._-]*/i
 
-let comment             = Util.comment
 let eol                 = Util.doseol
 let empty               = Util.empty_dos
 let indent              = Util.indent
 
+let comment_val_re      = /([^ \t\r\n](.|\\\\\r?\n)*[^ \\\t\r\n]|[^ \t\r\n])/
+let comment             = [ label "#comment" . del /[ \t]*#[ \t]*/ "# "
+                          . store comment_val_re . eol ]
+
 (* borrowed from shellvars.aug *)
 let char_arg_dir  = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'|\\\\ /
 let char_arg_sec  = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ /
index 94ffa3c..342c6fb 100644 (file)
@@ -120,5 +120,7 @@ let lns = ( Util.comment | Util.empty | directive )*
 let filter = incl "/etc/nginx/nginx.conf"
            . incl "/etc/nginx/conf.d/*.conf"
            . incl "/usr/portage/www-servers/nginx/files/nginx.conf"
+           . incl "/usr/local/etc/nginx/nginx.conf"
+           . incl "/usr/local/etc/nginx/conf.d/*.conf"
 
 let xfm = transform lns filter
index c6d35b1..c11d5c0 100644 (file)
@@ -35,7 +35,7 @@ module Ntp =
                       sep_spc . store word ]
         | [ sep_spc . key (/autokey|burst|iburst|noselect|preempt/ |
                            /prefer|true|dynamic/) ] in
-      let cmd = /server|peer|broadcast|manycastclient/
+      let cmd = /pool|server|peer|broadcast|manycastclient/
         | /multicastclient|manycastserver/ in
         record cmd opt*
 
@@ -67,10 +67,10 @@ module Ntp =
 
     (* Define restrict *)
     let restrict_record   =
-      let action    = [ label "action" . sep_spc . store word ] in
-      [ key "restrict" . sep_spc .
-          [ label "ipv6" . Util.del_str "-6" . sep_spc ]? .
-          store (word - "-6") . action* . eol ]
+      let ip6_restrict = [ label "ipv6" . sep_spc . Util.del_str "-6" ] in
+      let ip4_restrict = [ label "ipv4" . sep_spc . Util.del_str "-4" ] in
+      let action    = [ label "action" . sep_spc . store /[^,# \n\t-][^,# \n\t]*/ ] in
+      [ key "restrict" . (ip6_restrict | ip4_restrict)? . sep_spc . store /[^,# \n\t-][^,# \n\t]*/ . action* . eol ]
 
     (* Define statistics *)
     let statistics_flag (kw:string) = [ sep_spc . key kw ]
index 23b3c78..b1807a0 100644 (file)
@@ -48,11 +48,11 @@ module Pam =
   (* Shared with PamConf *)
   let record = [ label "optional" . del "-" "-" ]? .
                [ label "type" . store types ] .
-               Util.del_ws_tab .
+               Sep.space .
                [ label "control" . store control] .
-               Util.del_ws_tab .
+               Sep.space .
                [ label "module" . store word ] .
-               [ Util.del_ws_tab . label "argument" . store argument ]* .
+               [ Sep.space . label "argument" . store argument ]* .
                comment_or_eol
 
   let record_svc = [ seq "record" . indent . record ]
index 2b18515..925d197 100644 (file)
@@ -39,7 +39,7 @@ let service = Rx.word
 
 let record  = [ seq "record" . indent .
               [ label "service" . store service ] .
-              Util.del_ws_tab .
+              Sep.space .
               Pam.record ]
 
 let lns = ( empty | comment | include | record ) *
diff --git a/lenses/postfix_passwordmap.aug b/lenses/postfix_passwordmap.aug
new file mode 100644 (file)
index 0000000..eb24a9c
--- /dev/null
@@ -0,0 +1,51 @@
+(*
+Module: Postfix_Passwordmap
+  Parses /etc/postfix/*passwd
+
+Author: Anton Baranov <abaranov@linuxfoundation.org>
+
+About: Reference
+  This lens tries to keep as close as possible to `man 5 postconf` and
+  http://www.postfix.org/SASL_README.html#client_sasl_enable where possible.
+
+About: License
+   This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Configuration files
+   This lens applies to /etc/postfix/*passwd. See <filter>.
+
+About: Examples
+   The <Test_Postfix_Passwordmap> file contains various examples and tests.
+*)
+
+module Postfix_Passwordmap =
+
+autoload xfm
+
+(* View: space_or_eol *)
+let space_or_eol = del /([ \t]*\n)?[ \t]+/ " "
+
+(* View: word *)
+let word = store /[A-Za-z0-9@_\+\*.-]+/
+
+(* View: colon *)
+let colon = Sep.colon
+
+(* View: username *)
+let username = [ label "username" . word ]
+
+(* View: password *)
+let password = [ label "password" . (store Rx.space_in)? ]
+
+(* View: record *)
+let record = [ label "pattern" . store /\[?[A-Za-z0-9@\*.-]+\]?(:?[A-Za-z0-9]*)*/
+             . space_or_eol . username . colon . password
+             . Util.eol ]
+
+(* View: lns *)
+let lns = (Util.empty | Util.comment | record)*
+
+(* Variable: filter *)
+let filter = incl "/etc/postfix/*passwd"
+
+let xfm = transform lns filter
index 7fc78b4..7174959 100644 (file)
@@ -26,6 +26,11 @@ 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 = [ key /action|global|input|module|parser|timezone/ . Sep.lbracket
+                    . config_object_param+ . Sep.rbracket . Util.comment_or_eol ]
+
 (* View: users
    Map :omusrmsg: and a list of users, or a single *
 *)
@@ -58,7 +63,7 @@ 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 | prop_filter )*
+let entries = ( Syslog.empty | Syslog.comment | entry | macro | config_object | prop_filter )*
 
 let lns = entries . ( Syslog.program | Syslog.hostname )*
 
index 7da7779..377f00a 100644 (file)
@@ -290,6 +290,8 @@ module Shellvars =
                      . excl "/etc/default/rmt"
                      . excl "/etc/default/star"
                      . excl "/etc/default/whoopsie"
+                     . incl "/etc/profile"
+                     . incl "/etc/profile.d/*"
   let filter_misc    = incl "/etc/arno-iptables-firewall/debconf.cfg"
                      . incl "/etc/conf.d/*"
                      . incl "/etc/cron-apt/config"
@@ -302,6 +304,7 @@ module Shellvars =
                      . incl "/etc/cvs-pserver.conf"
                      . incl "/etc/devscripts.conf"
                      . incl "/etc/kamailio/kamctlrc"
+                     . incl "/etc/lbu/lbu.conf"
                      . incl "/etc/lintianrc"
                      . incl "/etc/lsb-release"
                      . incl "/etc/os-release"
@@ -313,6 +316,7 @@ module Shellvars =
                      . incl "/etc/ucf.conf"
                      . incl "/etc/locale.conf"
                      . incl "/etc/vconsole.conf"
+                     . incl "/etc/byobu/*"
 
   let filter = filter_sysconfig
              . filter_default
index 7d5e045..c860860 100644 (file)
@@ -583,3 +583,7 @@ test Httpd.lns get "RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTT
 test Httpd.lns get "<FilesMatch \ test\.php$></FilesMatch>\n" =
   { "FilesMatch"
     { "arg" = "\ test\.php$" } }
+
+(* Continuations in comments cause the comment to be continued without a new comment character *)
+test Httpd.lns get "#ServerRoot \\\n  /var/www\n" =
+  { "#comment" = "ServerRoot \\\n  /var/www" }
index e581f31..f6aaa2d 100644 (file)
@@ -119,6 +119,21 @@ interface listen 127.0.0.1
       { "action" = "nopeer" }
       { "action" = "noquery" } }
 
+  test Ntp.lns put
+    "restrict default kod nomodify notrap nopeer noquery\n"
+  after
+    insb "ipv4" "restrict/action[1]" =
+    "restrict -4 default kod nomodify notrap nopeer noquery\n"
+
+  test Ntp.lns get
+    "restrict -4 default notrap nomodify nopeer noquery\n" =
+    { "restrict" = "default"
+      { "ipv4" }
+      { "action" = "notrap" }
+      { "action" = "nomodify" }
+      { "action" = "nopeer" }
+      { "action" = "noquery" } }
+
   test Ntp.lns get
     "includefile /etc/ntp/crypto/pw\n" =
     { "includefile" = "/etc/ntp/crypto/pw" }
diff --git a/lenses/tests/test_postfix_passwordmap.aug b/lenses/tests/test_postfix_passwordmap.aug
new file mode 100644 (file)
index 0000000..4efd739
--- /dev/null
@@ -0,0 +1,43 @@
+(*
+Module: Test_Postfix_Passwordmap
+  Provides unit tests and examples for the <Postfix_Passwordmap> lens.
+*)
+
+module Test_Postfix_Passwordmap =
+
+(* View: conf *)
+let conf = "# comment
+*                               username:password
+[mail.isp.example]              username:password
+[mail.isp.example]:submission   username:password
+[mail.isp.example]:587          username:password
+mail.isp.example                username:password
+user@mail.isp.example           username:
+mail.isp.example
+        username2:password2
+"
+
+(* Test: Postfix_Passwordmap.lns *)
+test Postfix_Passwordmap.lns get conf =
+  { "#comment" = "comment" }
+  { "pattern" = "*"
+    { "username" = "username" }
+    { "password" = "password" } }
+  { "pattern" = "[mail.isp.example]"
+    { "username" = "username" }
+    { "password" = "password" } }
+  { "pattern" = "[mail.isp.example]:submission"
+    { "username" = "username" }
+    { "password" = "password" } }
+  { "pattern" = "[mail.isp.example]:587"
+    { "username" = "username" }
+    { "password" = "password" } }
+  { "pattern" = "mail.isp.example"
+    { "username" = "username" }
+    { "password" = "password" } }
+  { "pattern" = "user@mail.isp.example"
+    { "username" = "username" }
+    { "password" } }
+  { "pattern" = "mail.isp.example"
+    { "username" = "username2" }
+    { "password" = "password2" } }
index 6fcc6f5..27c7cea 100644 (file)
@@ -10,6 +10,10 @@ 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
+
+timezone(id=\"CET\" offset=\"+01:00\")
+
 $UDPServerRun 514
 $InputTCPServerRun 514
 $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
@@ -36,6 +40,16 @@ test Rsyslog.lns get conf =
   { "$ModLoad" = "imklog"
     { "#comment" = "provides kernel logging support (previously done by rklogd)" }
   }
+  { "module"
+    { "load" = "immark" }
+    { "#comment" = "provides --MARK-- message capability" }
+  }
+  {  }
+  { "timezone"
+    { "id" = "CET" }
+    { "offset" = "+01:00" }
+  }
+  {  }
   { "$UDPServerRun" = "514" }
   { "$InputTCPServerRun" = "514" }
   { "$ActionFileDefaultTemplate" = "RSYSLOG_TraditionalFileFormat" }
index 278910e..9db0a11 100644 (file)
@@ -40,6 +40,7 @@ chroot_list_file=/etc/vsftpd/chroot_list
 pam_service_name=vsftpd
 userlist_enable=YES
 tcp_wrappers=YES
+allow_writeable_chroot=YES
 
 "
 
@@ -68,5 +69,6 @@ test Vsftpd.lns get conf =
   { "pam_service_name" = "vsftpd" }
   { "userlist_enable" = "YES" }
   { "tcp_wrappers" = "YES" }
+  { "allow_writeable_chroot" = "YES" }
   {}
 
index eb0e96f..a4096b7 100644 (file)
@@ -8,7 +8,7 @@ let eol = Util.del_str "\n"
 let empty = Util.empty
 let comment = Util.comment
 
-let bool_option_re = /anonymous_enable|isolate|isolate_network|local_enable|pasv_enable|port_enable|chroot_local_user|write_enable|anon_upload_enable|anon_mkdir_write_enable|anon_other_write_enable|chown_uploads|connect_from_port_20|xferlog_enable|dirmessage_enable|anon_world_readable_only|async_abor_enable|ascii_upload_enable|ascii_download_enable|one_process_model|xferlog_std_format|pasv_promiscuous|deny_email_enable|chroot_list_enable|setproctitle_enable|text_userdb_names|ls_recurse_enable|log_ftp_protocol|guest_enable|userlist_enable|userlist_deny|use_localtime|check_shell|hide_ids|listen|port_promiscuous|passwd_chroot_enable|no_anon_password|tcp_wrappers|use_sendfile|force_dot_files|listen_ipv6|dual_log_enable|syslog_enable|background|virtual_use_local_privs|session_support|download_enable|dirlist_enable|chmod_enable|secure_email_list_enable|run_as_launching_user|no_log_lock|ssl_enable|allow_anon_ssl|force_local_logins_ssl|force_local_data_ssl|ssl_sslv2|ssl_sslv3|ssl_tlsv1|tilde_user_enable|force_anon_logins_ssl|force_anon_data_ssl|mdtm_write|lock_upload_files|pasv_addr_resolve|debug_ssl|require_cert|validate_cert|require_ssl_reuse/
+let bool_option_re = /anonymous_enable|isolate|isolate_network|local_enable|pasv_enable|port_enable|chroot_local_user|write_enable|anon_upload_enable|anon_mkdir_write_enable|anon_other_write_enable|chown_uploads|connect_from_port_20|xferlog_enable|dirmessage_enable|anon_world_readable_only|async_abor_enable|ascii_upload_enable|ascii_download_enable|one_process_model|xferlog_std_format|pasv_promiscuous|deny_email_enable|chroot_list_enable|setproctitle_enable|text_userdb_names|ls_recurse_enable|log_ftp_protocol|guest_enable|userlist_enable|userlist_deny|use_localtime|check_shell|hide_ids|listen|port_promiscuous|passwd_chroot_enable|no_anon_password|tcp_wrappers|use_sendfile|force_dot_files|listen_ipv6|dual_log_enable|syslog_enable|background|virtual_use_local_privs|session_support|download_enable|dirlist_enable|chmod_enable|secure_email_list_enable|run_as_launching_user|no_log_lock|ssl_enable|allow_anon_ssl|force_local_logins_ssl|force_local_data_ssl|ssl_sslv2|ssl_sslv3|ssl_tlsv1|tilde_user_enable|force_anon_logins_ssl|force_anon_data_ssl|mdtm_write|lock_upload_files|pasv_addr_resolve|debug_ssl|require_cert|validate_cert|require_ssl_reuse|allow_writeable_chroot/
 
 let uint_option_re = /accept_timeout|connect_timeout|local_umask|anon_umask|ftp_data_port|idle_session_timeout|data_connection_timeout|pasv_min_port|pasv_max_port|anon_max_rate|local_max_rate|listen_port|max_clients|file_open_mode|max_per_ip|trans_chunk_size|delay_failed_login|delay_successful_login|max_login_fails|chown_upload_mode/
 
index b29e17a..9d1de03 100644 (file)
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
+.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.31)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 .\" ========================================================================
 .\"
 .IX Title "AUGTOOL 1"
-.TH AUGTOOL 1 "2015-10-03" "Augeas 1.4.0" "Augeas"
+.TH AUGTOOL 1 "2016-08-05" "Augeas 1.5.0" "Augeas"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -182,6 +182,14 @@ directories set here are searched before any directories specified in the
 .IX Item "-t, --transform=XFM"
 Add a file transform; uses the 'transform' command syntax,
 e.g. \f(CW\*(C`\-t \*(AqFstab incl /etc/fstab.bak\*(Aq\*(C'\fR.
+.IP "\fB\-l\fR, \fB\-\-load\-file\fR=\fI\s-1FILE\s0\fR" 4
+.IX Item "-l, --load-file=FILE"
+Load an invididual \s-1FILE\s0 into the tree. The lens to use is determined
+automatically (based on autoload information in the lenses) and will be the
+same that is used for this file when the entire tree is loaded. The option
+can be specified multiple times to load several files, e.g. \f(CW\*(C`\-l /etc/fstab
+\&\-l /etc/hosts\*(C'\fR. This lens implies \f(CW\*(C`\-\-noload\*(C'\fR so that only the files
+specified with this option will be loaded.
 .IP "\fB\-f\fR, \fB\-\-file\fR=\fI\s-1FILE\s0\fR" 4
 .IX Item "-f, --file=FILE"
 Read commands from \s-1FILE.\s0
@@ -269,6 +277,11 @@ full lens name.  If a module name is given, then \*(L"lns\*(R" will be the lens
 assumed.  The \s-1FILTER\s0 must be either \*(L"incl\*(R" or \*(L"excl\*(R".  If the filter is
 \&\*(L"incl\*(R",  the \s-1FILE\s0 will be parsed by the \s-1LENS. \s0 If the filter is \*(L"excl\*(R",
 the \s-1FILE\s0 will be excluded from the \s-1LENS. FILE\s0 may contain wildcards.
+.IP "\fBload-file\fR <\s-1FILE\s0>" 4
+.IX Item "load-file <FILE>"
+Load a specific \s-1FILE,\s0 automatically determining the proper lens from the
+information in \fI/augeas/load\fR; without further intervention, the lens that
+would oridnarily be used for this file will be used.
 .SS "\s-1READ COMMANDS\s0"
 .IX Subsection "READ COMMANDS"
 The following commands are used to retrieve data from the Augeas tree.
index 6169a41..dadfecb 100644 (file)
@@ -54,6 +54,15 @@ F</usr/share/augeas/lenses> and F</usr/share/augeas/lenses/dist>.
 Add a file transform; uses the 'transform' command syntax,
 e.g. C<-t 'Fstab incl /etc/fstab.bak'>.
 
+=item B<-l>, B<--load-file>=I<FILE>
+
+Load an invididual FILE into the tree. The lens to use is determined
+automatically (based on autoload information in the lenses) and will be the
+same that is used for this file when the entire tree is loaded. The option
+can be specified multiple times to load several files, e.g. C<-l /etc/fstab
+-l /etc/hosts>. This lens implies C<--noload> so that only the files
+specified with this option will be loaded.
+
 =item B<-f>, B<--file>=I<FILE>
 
 Read commands from FILE.
@@ -164,6 +173,12 @@ assumed.  The FILTER must be either "incl" or "excl".  If the filter is
 "incl",  the FILE will be parsed by the LENS.  If the filter is "excl",
 the FILE will be excluded from the LENS. FILE may contain wildcards.
 
+=item B<load-file> E<lt>FILEE<gt>
+
+Load a specific FILE, automatically determining the proper lens from the
+information in F</augeas/load>; without further intervention, the lens that
+would oridnarily be used for this file will be used.
+
 =back
 
 =head2 READ COMMANDS
index 72221ae..5467541 100644 (file)
@@ -767,7 +767,7 @@ int aug_load(struct augeas *aug) {
 
     list_for_each(xfm, load->children) {
         if (transform_validate(aug, xfm) == 0)
-            transform_load(aug, xfm);
+            transform_load(aug, xfm, NULL);
     }
 
     /* This makes it possible to spot 'directories' that are now empty
@@ -2020,6 +2020,43 @@ int aug_escape_name(augeas *aug, const char *in, char **out) {
     return result;
 }
 
+int aug_load_file(struct augeas *aug, const char *file) {
+    int result = -1;
+    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
+    struct tree *load = tree_child_cr(meta, s_load);
+    char *tree_path = NULL;
+    bool found = false;
+
+    api_entry(aug);
+
+    ERR_NOMEM(load == NULL, aug);
+
+    list_for_each(xfm, load->children)  {
+        if (filter_matches(xfm, file)) {
+            transform_load(aug, xfm, file);
+            found = true;
+            break;
+        }
+    }
+
+    ERR_THROW(!found, aug, AUG_ENOLENS,
+              "can not determine lens to load file %s", file);
+
+    /* Mark the nodes we just loaded as clean so they won't get saved
+       without additional modifications */
+    xasprintf(&tree_path, "/files/%s", file);
+    struct tree *t = tree_fpath(aug, tree_path);
+    if (t != NULL) {
+        tree_clean(t);
+    }
+
+    result = 0;
+error:
+    api_exit(aug);
+    free(tree_path);
+    return result;
+}
+
 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
     struct pathx *p;
     int result;
index f4011f4..dceb934 100644 (file)
@@ -424,6 +424,21 @@ int aug_to_xml(const augeas *aug, const char *path, xmlNode **xmldoc,
 int aug_transform(augeas *aug, const char *lens, const char *file, int excl);
 
 /*
+ * Function: aug_load_file
+ *
+ * Load a FILE using the lens that would ordinarily be used by aug_load,
+ * i.e. the lens whose autoload statement matches the FILE. Similar to
+ * aug_load, this function returns successfully even if FILE does not exist
+ * or if the FILE can not be processed by the associated lens. It is an
+ * error though if no lens can be found to process FILE. In that case, the
+ * error code in AUG will be set to AUG_ENOLENS.
+ *
+ * Returns:
+ * 0 on success, -1 on failure
+ */
+int aug_load_file(augeas *aug, const char *file);
+
+/*
  * Function: aug_srun
  *
  * Run one or more newline-separated commands. The output of the commands
index 0c4d7c4..7417597 100644 (file)
@@ -70,3 +70,8 @@ AUGEAS_0.20.0 {
     global:
       aug_escape_name;
 } AUGEAS_0.18.0;
+
+AUGEAS_0.21.0 {
+    global:
+      aug_load_file;
+} AUGEAS_0.20.0;
index 1dd2c91..ce4bbc0 100644 (file)
@@ -1010,6 +1010,33 @@ static const struct command_def cmd_transform_def = {
     .help = cmd_transform_help
 };
 
+static void cmd_load_file(struct command *cmd) {
+    const char *file = arg_value(cmd, "file");
+    int r = 0;
+
+    r = aug_load_file(cmd->aug, file);
+    if (r < 0)
+      ERR_REPORT(cmd, AUG_ECMDRUN,
+          "Failed to load file %s", file);
+}
+
+static const struct command_opt_def cmd_load_file_opts[] = {
+    { .type = CMD_PATH, .name = "file", .optional = false,
+      .help = "the file to load" },
+    CMD_OPT_DEF_LAST
+};
+
+static const char const cmd_load_file_help[] =
+    "Load a specific FILE, using autoload statements.\n";
+
+static const struct command_def cmd_load_file_def = {
+    .name = "load-file",
+    .opts = cmd_load_file_opts,
+    .handler = cmd_load_file,
+    .synopsis = "load a specific file",
+    .help = cmd_load_file_help
+};
+
 static void cmd_save(struct command *cmd) {
     int r;
     r = aug_save(cmd->aug);
@@ -1297,6 +1324,7 @@ static const struct command_grp_def cmd_grp_admin_def = {
         &cmd_save_def,
         &cmd_store_def,
         &cmd_transform_def,
+        &cmd_load_file_def,
         &cmd_def_last
     }
 };
index 0603c6d..1aa58ec 100644 (file)
@@ -47,7 +47,9 @@ static unsigned int flags = AUG_NONE;
 const char *root = NULL;
 char *loadpath = NULL;
 char *transforms = NULL;
+char *loadonly = NULL;
 size_t transformslen = 0;
+size_t loadonlylen = 0;
 const char *inputfile = NULL;
 int echo_commands = 0;         /* Gets also changed in main_loop */
 bool print_version = false;
@@ -177,7 +179,7 @@ static char *readline_command_generator(const char *text, int state) {
         "quit", "clear", "defnode", "defvar",
         "get", "label", "ins", "load", "ls", "match",
         "mv", "cp", "rename", "print", "dump-xml", "rm", "save", "set", "setm",
-        "clearm", "span", "store", "retrieve", "transform",
+        "clearm", "span", "store", "retrieve", "transform", "load-file",
         "help", "touch", "insert", "move", "copy", "errors", NULL };
 
     static int current = 0;
@@ -291,27 +293,28 @@ static void help(void) {
     fprintf(stderr, "Run '%s help' to get a list of possible commands.\n",
             progname);
     fprintf(stderr, "\nOptions:\n\n");
-    fprintf(stderr, "  -c, --typecheck      typecheck lenses\n");
-    fprintf(stderr, "  -b, --backup         preserve originals of modified files with\n"
-                    "                       extension '.augsave'\n");
-    fprintf(stderr, "  -n, --new            save changes in files with extension '.augnew',\n"
-                    "                       leave original unchanged\n");
-    fprintf(stderr, "  -r, --root ROOT      use ROOT as the root of the filesystem\n");
-    fprintf(stderr, "  -I, --include DIR    search DIR for modules; can be given multiple times\n");
-    fprintf(stderr, "  -t, --transform XFM  add a file transform; uses the 'transform' command\n"
-                    "                       syntax, e.g. -t 'Fstab incl /etc/fstab.bak'\n");
-    fprintf(stderr, "  -e, --echo           echo commands when reading from a file\n");
-    fprintf(stderr, "  -f, --file FILE      read commands from FILE\n");
-    fprintf(stderr, "  -s, --autosave       automatically save at the end of instructions\n");
-    fprintf(stderr, "  -i, --interactive    run an interactive shell after evaluating\n"
-                    "                       the commands in STDIN and FILE\n");
-    fprintf(stderr, "  -S, --nostdinc       do not search the builtin default directories\n"
-                    "                       for modules\n");
-    fprintf(stderr, "  -L, --noload         do not load any files into the tree on startup\n");
-    fprintf(stderr, "  -A, --noautoload     do not autoload modules from the search path\n");
-    fprintf(stderr, "  --span               load span positions for nodes related to a file\n");
-    fprintf(stderr, "  --timing             after executing each command, show how long it took\n");
-    fprintf(stderr, "  --version            print version information and exit.\n");
+    fprintf(stderr, "  -c, --typecheck        typecheck lenses\n");
+    fprintf(stderr, "  -b, --backup           preserve originals of modified files with\n"
+                    "                         extension '.augsave'\n");
+    fprintf(stderr, "  -n, --new              save changes in files with extension '.augnew',\n"
+                    "                         leave original unchanged\n");
+    fprintf(stderr, "  -r, --root ROOT        use ROOT as the root of the filesystem\n");
+    fprintf(stderr, "  -I, --include DIR      search DIR for modules; can be given multiple times\n");
+    fprintf(stderr, "  -t, --transform XFM    add a file transform; uses the 'transform' command\n"
+                    "                         syntax, e.g. -t 'Fstab incl /etc/fstab.bak'\n");
+    fprintf(stderr, "  -l, --load-file FILE   load individual FILE in the tree\n");
+    fprintf(stderr, "  -e, --echo             echo commands when reading from a file\n");
+    fprintf(stderr, "  -f, --file FILE        read commands from FILE\n");
+    fprintf(stderr, "  -s, --autosave         automatically save at the end of instructions\n");
+    fprintf(stderr, "  -i, --interactive      run an interactive shell after evaluating\n"
+                    "                         the commands in STDIN and FILE\n");
+    fprintf(stderr, "  -S, --nostdinc         do not search the builtin default directories\n"
+                    "                         for modules\n");
+    fprintf(stderr, "  -L, --noload           do not load any files into the tree on startup\n");
+    fprintf(stderr, "  -A, --noautoload       do not autoload modules from the search path\n");
+    fprintf(stderr, "  --span                 load span positions for nodes related to a file\n");
+    fprintf(stderr, "  --timing               after executing each command, show how long it took\n");
+    fprintf(stderr, "  --version              print version information and exit.\n");
 
     exit(EXIT_FAILURE);
 }
@@ -332,6 +335,7 @@ static void parse_opts(int argc, char **argv) {
         { "root",        1, 0, 'r' },
         { "include",     1, 0, 'I' },
         { "transform",   1, 0, 't' },
+        { "load-file",   1, 0, 'l' },
         { "echo",        0, 0, 'e' },
         { "file",        1, 0, 'f' },
         { "autosave",    0, 0, 's' },
@@ -346,7 +350,7 @@ static void parse_opts(int argc, char **argv) {
     };
     int idx;
 
-    while ((opt = getopt_long(argc, argv, "hnbcr:I:t:ef:siSLA", options, &idx)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hnbcr:I:t:l:ef:siSLA", options, &idx)) != -1) {
         switch(opt) {
         case 'c':
             flags |= AUG_TYPE_CHECK;
@@ -369,6 +373,11 @@ static void parse_opts(int argc, char **argv) {
         case 't':
             argz_add(&transforms, &transformslen, optarg);
             break;
+        case 'l':
+            // --load-file implies --noload
+            flags |= AUG_NO_LOAD;
+            argz_add(&loadonly, &loadonlylen, optarg);
+            break;
         case 'e':
             echo_commands = 1;
             break;
@@ -649,6 +658,24 @@ static void add_transforms(char *ts, size_t tslen) {
     }
 }
 
+static void load_files(char *ts, size_t tslen) {
+    char *command;
+    int r;
+    char *t = NULL;
+
+    while ((t = argz_next(ts, tslen, 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);
+
+        r = aug_srun(aug, stdout, command);
+        if (r < 0)
+            fprintf(stderr, "error: Failed to load file %s: %s\n", t, aug_error_message(aug));
+
+        free(command);
+    }
+}
+
 int main(int argc, char **argv) {
     int r;
     struct timeval start, stop;
@@ -677,6 +704,7 @@ int main(int argc, char **argv) {
             print_aug_error();
         exit(EXIT_FAILURE);
     }
+    load_files(loadonly, loadonlylen);
     add_transforms(transforms, transformslen);
     if (print_version) {
         print_version_info();
index 83ed388..ec20676 100644 (file)
--- a/src/fa.c
+++ b/src/fa.c
@@ -2773,6 +2773,8 @@ static struct fa *expand_alphabet(struct fa *fa, int add_marker,
             continue;
 
         struct state *r = add_state(fa, 0);
+        if (r == NULL)
+            goto error;
         r->trans = p->trans;
         r->tused = p->tused;
         r->tsize = p->tsize;
index db74c17..847b068 100644 (file)
@@ -52,6 +52,7 @@ int pathjoin(char **path, int nseg, ...) {
             len += strlen(*path) + 1;
             if (REALLOC_N(*path, len) == -1) {
                 FREE(*path);
+                va_end(ap);
                 return -1;
             }
             if (strlen(*path) == 0 || (*path)[strlen(*path)-1] != SEP)
@@ -60,8 +61,10 @@ int pathjoin(char **path, int nseg, ...) {
                 seg += 1;
             strcat(*path, seg);
         } else {
-            if ((*path = malloc(len)) == NULL)
+            if ((*path = malloc(len)) == NULL) {
+                va_end(ap);
                 return -1;
+            }
             strcpy(*path, seg);
         }
     }
index 5e69767..bebbf78 100644 (file)
@@ -184,7 +184,7 @@ struct value {
     enum type tag;
     union {
         struct nodeset  *nodeset;     /* T_NODESET */
-        int              number;      /* T_NUMBER  */
+        int64_t          number;      /* T_NUMBER  */
         char            *string;      /* T_STRING  */
         bool             boolval;     /* T_BOOLEAN */
         struct regexp   *regexp;      /* T_REGEXP  */
index 1a59187..e717390 100644 (file)
@@ -283,7 +283,7 @@ static int filter_generate(struct tree *xfm, const char *root,
     goto done;
 }
 
-static int filter_matches(struct tree *xfm, const char *path) {
+int filter_matches(struct tree *xfm, const char *path) {
     int found = 0;
     list_for_each(f, xfm->children) {
         if (is_incl(f) && fnmatch_normalize(f->value, path, fnm_flags) == 0) {
@@ -811,7 +811,7 @@ static struct tree *file_info(struct augeas *aug, const char *fname) {
     return result;
 }
 
-int transform_load(struct augeas *aug, struct tree *xfm) {
+int transform_load(struct augeas *aug, struct tree *xfm, const char *file) {
     int nmatches = 0;
     char **matches;
     const char *lens_name;
@@ -822,12 +822,17 @@ int transform_load(struct augeas *aug, struct tree *xfm) {
         // FIXME: Record an error and return 0
         return -1;
     }
+
     r = filter_generate(xfm, aug->root, &nmatches, &matches);
     if (r == -1)
         return -1;
     for (int i=0; i < nmatches; i++) {
         const char *filename = matches[i] + strlen(aug->root) - 1;
         struct tree *finfo = file_info(aug, filename);
+
+        if (file != NULL && STRNEQ(filename, file))
+          continue;
+
         if (finfo != NULL && !finfo->dirty &&
             tree_child(finfo, s_lens) != NULL) {
             const char *s = xfm_lens_name(finfo);
index 5318602..ddc9de4 100644 (file)
@@ -65,8 +65,14 @@ int transform_validate(struct augeas *aug, struct tree *xfm);
  * applying the TRANSFORM's lens to their contents and putting the
  * resulting tree under "/files" + filename. Also stores some information
  * about filename underneath "/augeas/files" + filename
+ * If a FILE is passed, only this FILE will be loaded.
  */
-int transform_load(struct augeas *aug, struct tree *xfm);
+int transform_load(struct augeas *aug, struct tree *xfm, const char *file);
+
+/* Return 1 if TRANSFORM applies to PATH, 0 otherwise.
+ * PATH must not include "/files/".
+ */
+int filter_matches(struct tree *xfm, const char *path);
 
 /* Return 1 if TRANSFORM applies to PATH, 0 otherwise. The TRANSFORM
  * applies to PATH if (1) PATH starts with "/files/" and (2) the rest of
index 3697862..1ddcc01 100644 (file)
@@ -150,6 +150,7 @@ lens_tests =                        \
   lens-postfix_access.sh \
   lens-postfix_main.sh         \
   lens-postfix_master.sh       \
+  lens-postfix_passwordmap.sh \
   lens-postfix_sasl_smtpd.sh \
   lens-postfix_transport.sh    \
   lens-postfix_virtual.sh      \
index 9d739ef..f3c8858 100644 (file)
@@ -663,6 +663,39 @@ static void testRm(CuTest *tc) {
     CuAssertIntEquals(tc, 5, r);
 }
 
+static void testLoadFile(CuTest *tc) {
+    struct augeas *aug;
+    const char *value;
+    int r;
+
+    aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
+    CuAssertPtrNotNull(tc, aug);
+    CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug));
+
+    /* augeas should load a single file */
+    r = aug_load_file(aug, "/etc/fstab");
+    CuAssertRetSuccess(tc, r);
+    r = aug_get(aug, "/files/etc/fstab/1/vfstype", &value);
+    CuAssertIntEquals(tc, 1, r);
+    CuAssertPtrNotNull(tc, value);
+
+    /* Only one file should be loaded */
+    r = aug_match(aug, "/files/etc/*", NULL);
+    CuAssertIntEquals(tc, 1, r);
+
+    /* augeas should return an error when no lens can be found for a file */
+    r = aug_load_file(aug, "/etc/unknown.conf");
+    CuAssertIntEquals(tc, -1, r);
+    CuAssertIntEquals(tc, AUG_ENOLENS, aug_error(aug));
+
+    /* augeas should return without an error when trying to load a
+       nonexistant file that would be handled by a lens */
+    r = aug_load_file(aug, "/etc/mtab");
+    CuAssertRetSuccess(tc, r);
+    r = aug_match(aug, "/files/etc/mtab", NULL);
+    CuAssertIntEquals(tc, 0, r);
+}
+
 int main(void) {
     char *output = NULL;
     CuSuite* suite = CuSuiteNew();
@@ -683,6 +716,7 @@ int main(void) {
     SUITE_ADD_TEST(suite, testTextRetrieve);
     SUITE_ADD_TEST(suite, testAugEscape);
     SUITE_ADD_TEST(suite, testRm);
+    SUITE_ADD_TEST(suite, testLoadFile);
 
     abs_top_srcdir = getenv("abs_top_srcdir");
     if (abs_top_srcdir == NULL)
index 976cc66..afe17d8 100644 (file)
@@ -15,4 +15,4 @@ diff='--- /etc/pam.d/newrole
  account    include\tsystem-auth
  password   include\tsystem-auth
  session    required\tpam_namespace.so unmnt_remnt no_unmount_on_close
-+auth\tinclude\tsystem-auth'
++auth include system-auth'
index 7caf7ef..8f749fc 100644 (file)
@@ -14,6 +14,6 @@ diff='--- /etc/pam.d/newrole
  #%PAM-1.0
  auth       include\tsystem-auth
  account    include\tsystem-auth
-+session\tinclude\tsystem-auth
++session include system-auth
  password   include\tsystem-auth
  session    required\tpam_namespace.so unmnt_remnt no_unmount_on_close'
index 47624db..54e3493 100644 (file)
@@ -13,5 +13,5 @@ diff='--- /etc/pam.d/newrole
  auth       include\tsystem-auth
  account    include\tsystem-auth
 -password   include\tsystem-auth
-+password   include\tother_module\tother_module_opts
++password   include\tother_module other_module_opts
  session    required\tpam_namespace.so unmnt_remnt no_unmount_on_close'