From 28c12afefeedee77921efcc886a435078b69d673 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Thu, 6 Oct 2016 13:47:13 +0900 Subject: [PATCH] Imported Upstream version 1.6.0 Change-Id: Ib488a1803305cd67ce55b116ebba415d68c0e787 Signed-off-by: DongHun Kwak --- AUTHORS | 4 ++ NEWS | 28 +++++++++++- configure.ac | 6 +-- doc/naturaldocs/conf/lenses/Languages.txt | 2 +- doc/naturaldocs/conf/lenses/Menu.txt | 2 + lenses/httpd.aug | 5 ++- lenses/nginx.aug | 2 + lenses/ntp.aug | 10 ++--- lenses/pam.aug | 6 +-- lenses/pamconf.aug | 2 +- lenses/postfix_passwordmap.aug | 51 +++++++++++++++++++++ lenses/rsyslog.aug | 7 ++- lenses/shellvars.aug | 4 ++ lenses/tests/test_httpd.aug | 4 ++ lenses/tests/test_ntp.aug | 15 +++++++ lenses/tests/test_postfix_passwordmap.aug | 43 ++++++++++++++++++ lenses/tests/test_rsyslog.aug | 14 ++++++ lenses/tests/test_vsftpd.aug | 2 + lenses/vsftpd.aug | 2 +- man/augtool.1 | 17 ++++++- man/augtool.pod | 15 +++++++ src/augeas.c | 39 +++++++++++++++- src/augeas.h | 15 +++++++ src/augeas_sym.version | 5 +++ src/augrun.c | 28 ++++++++++++ src/augtool.c | 74 +++++++++++++++++++++---------- src/fa.c | 2 + src/internal.c | 5 ++- src/pathx.c | 2 +- src/transform.c | 9 +++- src/transform.h | 8 +++- tests/Makefile.am | 1 + tests/test-api.c | 34 ++++++++++++++ tests/test-augtool/rec-append-record.sh | 2 +- tests/test-augtool/rec-ins-record.sh | 2 +- tests/test-augtool/rec-mod-field.sh | 2 +- 36 files changed, 418 insertions(+), 51 deletions(-) create mode 100644 lenses/postfix_passwordmap.aug create mode 100644 lenses/tests/test_postfix_passwordmap.aug diff --git a/AUTHORS b/AUTHORS index 99d6174..5c25c34 100644 --- a/AUTHORS +++ b/AUTHORS @@ -139,3 +139,7 @@ Contributions by: Chris Reeves Gerlof Fokkema Daniel Trebbien + Robert Moucha + Craig Miskell + Anton Baranov + Josef Reidinger diff --git a/NEWS b/NEWS index 7fdf6cd..e4dd082 100644 --- 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 diff --git a/configure.ac b/configure.ac index 72b6984..ce1ff70 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/naturaldocs/conf/lenses/Languages.txt b/doc/naturaldocs/conf/lenses/Languages.txt index 499f12a..47a9622 100644 --- a/doc/naturaldocs/conf/lenses/Languages.txt +++ b/doc/naturaldocs/conf/lenses/Languages.txt @@ -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 diff --git a/doc/naturaldocs/conf/lenses/Menu.txt b/doc/naturaldocs/conf/lenses/Menu.txt index 78820a2..b9410c7 100644 --- a/doc/naturaldocs/conf/lenses/Menu.txt +++ b/doc/naturaldocs/conf/lenses/Menu.txt @@ -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) diff --git a/lenses/httpd.aug b/lenses/httpd.aug index 7a5129b..2729f4b 100644 --- a/lenses/httpd.aug +++ b/lenses/httpd.aug @@ -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>])|\\\\"|\\\\'|\\\\ / diff --git a/lenses/nginx.aug b/lenses/nginx.aug index 94ffa3c..342c6fb 100644 --- a/lenses/nginx.aug +++ b/lenses/nginx.aug @@ -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 diff --git a/lenses/ntp.aug b/lenses/ntp.aug index c6d35b1..c11d5c0 100644 --- a/lenses/ntp.aug +++ b/lenses/ntp.aug @@ -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 ] diff --git a/lenses/pam.aug b/lenses/pam.aug index 23b3c78..b1807a0 100644 --- a/lenses/pam.aug +++ b/lenses/pam.aug @@ -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 ] diff --git a/lenses/pamconf.aug b/lenses/pamconf.aug index 2b18515..925d197 100644 --- a/lenses/pamconf.aug +++ b/lenses/pamconf.aug @@ -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 index 0000000..eb24a9c --- /dev/null +++ b/lenses/postfix_passwordmap.aug @@ -0,0 +1,51 @@ +(* +Module: Postfix_Passwordmap + Parses /etc/postfix/*passwd + +Author: Anton Baranov + +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 . + +About: Examples + The 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 diff --git a/lenses/rsyslog.aug b/lenses/rsyslog.aug index 7fc78b4..7174959 100644 --- a/lenses/rsyslog.aug +++ b/lenses/rsyslog.aug @@ -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 )* diff --git a/lenses/shellvars.aug b/lenses/shellvars.aug index 7da7779..377f00a 100644 --- a/lenses/shellvars.aug +++ b/lenses/shellvars.aug @@ -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 diff --git a/lenses/tests/test_httpd.aug b/lenses/tests/test_httpd.aug index 7d5e045..c860860 100644 --- a/lenses/tests/test_httpd.aug +++ b/lenses/tests/test_httpd.aug @@ -583,3 +583,7 @@ test Httpd.lns get "RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTT test Httpd.lns get "\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" } diff --git a/lenses/tests/test_ntp.aug b/lenses/tests/test_ntp.aug index e581f31..f6aaa2d 100644 --- a/lenses/tests/test_ntp.aug +++ b/lenses/tests/test_ntp.aug @@ -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 index 0000000..4efd739 --- /dev/null +++ b/lenses/tests/test_postfix_passwordmap.aug @@ -0,0 +1,43 @@ +(* +Module: Test_Postfix_Passwordmap + Provides unit tests and examples for the 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" } } diff --git a/lenses/tests/test_rsyslog.aug b/lenses/tests/test_rsyslog.aug index 6fcc6f5..27c7cea 100644 --- a/lenses/tests/test_rsyslog.aug +++ b/lenses/tests/test_rsyslog.aug @@ -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" } diff --git a/lenses/tests/test_vsftpd.aug b/lenses/tests/test_vsftpd.aug index 278910e..9db0a11 100644 --- a/lenses/tests/test_vsftpd.aug +++ b/lenses/tests/test_vsftpd.aug @@ -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" } {} diff --git a/lenses/vsftpd.aug b/lenses/vsftpd.aug index eb0e96f..a4096b7 100644 --- a/lenses/vsftpd.aug +++ b/lenses/vsftpd.aug @@ -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/ diff --git a/man/augtool.1 b/man/augtool.1 index b29e17a..9d1de03 100644 --- a/man/augtool.1 +++ b/man/augtool.1 @@ -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: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .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 " +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. diff --git a/man/augtool.pod b/man/augtool.pod index 6169a41..dadfecb 100644 --- a/man/augtool.pod +++ b/man/augtool.pod @@ -54,6 +54,15 @@ F and F. 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 + +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 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 EFILEE + +Load a specific FILE, automatically determining the proper lens from the +information in F; without further intervention, the lens that +would oridnarily be used for this file will be used. + =back =head2 READ COMMANDS diff --git a/src/augeas.c b/src/augeas.c index 72221ae..5467541 100644 --- a/src/augeas.c +++ b/src/augeas.c @@ -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; diff --git a/src/augeas.h b/src/augeas.h index f4011f4..dceb934 100644 --- a/src/augeas.h +++ b/src/augeas.h @@ -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 diff --git a/src/augeas_sym.version b/src/augeas_sym.version index 0c4d7c4..7417597 100644 --- a/src/augeas_sym.version +++ b/src/augeas_sym.version @@ -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; diff --git a/src/augrun.c b/src/augrun.c index 1dd2c91..ce4bbc0 100644 --- a/src/augrun.c +++ b/src/augrun.c @@ -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 } }; diff --git a/src/augtool.c b/src/augtool.c index 0603c6d..1aa58ec 100644 --- a/src/augtool.c +++ b/src/augtool.c @@ -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(); diff --git a/src/fa.c b/src/fa.c index 83ed388..ec20676 100644 --- 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; diff --git a/src/internal.c b/src/internal.c index db74c17..847b068 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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); } } diff --git a/src/pathx.c b/src/pathx.c index 5e69767..bebbf78 100644 --- a/src/pathx.c +++ b/src/pathx.c @@ -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 */ diff --git a/src/transform.c b/src/transform.c index 1a59187..e717390 100644 --- a/src/transform.c +++ b/src/transform.c @@ -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); diff --git a/src/transform.h b/src/transform.h index 5318602..ddc9de4 100644 --- a/src/transform.h +++ b/src/transform.h @@ -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 diff --git a/tests/Makefile.am b/tests/Makefile.am index 3697862..1ddcc01 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 \ diff --git a/tests/test-api.c b/tests/test-api.c index 9d739ef..f3c8858 100644 --- a/tests/test-api.c +++ b/tests/test-api.c @@ -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) diff --git a/tests/test-augtool/rec-append-record.sh b/tests/test-augtool/rec-append-record.sh index 976cc66..afe17d8 100644 --- a/tests/test-augtool/rec-append-record.sh +++ b/tests/test-augtool/rec-append-record.sh @@ -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' diff --git a/tests/test-augtool/rec-ins-record.sh b/tests/test-augtool/rec-ins-record.sh index 7caf7ef..8f749fc 100644 --- a/tests/test-augtool/rec-ins-record.sh +++ b/tests/test-augtool/rec-ins-record.sh @@ -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' diff --git a/tests/test-augtool/rec-mod-field.sh b/tests/test-augtool/rec-mod-field.sh index 47624db..54e3493 100644 --- a/tests/test-augtool/rec-mod-field.sh +++ b/tests/test-augtool/rec-mod-field.sh @@ -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' -- 2.7.4