This adds a new function shellquote() which can be used for quoting arguments in shell commands used in the exec type.
This only supports Unixoid operating systems. Other systems would likely require some other quoting. Signed-off-by: Thomas Bellman <[email protected]> --- lib/puppet/parser/functions/shellquote.rb | 41 +++++++++++++ spec/unit/parser/functions/shellquote.rb | 92 +++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 0 deletions(-) create mode 100644 lib/puppet/parser/functions/shellquote.rb create mode 100755 spec/unit/parser/functions/shellquote.rb diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb new file mode 100644 index 0000000..6c99452 --- /dev/null +++ b/lib/puppet/parser/functions/shellquote.rb @@ -0,0 +1,41 @@ +module Puppet::Parser::Functions + + Safe = 'a-za-z...@%_+=:,./-' # Safe unquoted + Dangerous = '!"`$\\' # Unsafe inside double quotes + + newfunction(:shellquote, :type => :rvalue, :doc => "\ + Quote and concatenate arguments for use in Bourne shell. + + Each argument is quoted separately, and then all are concatenated + with spaces. If an argument is an array, the elements of that + array is interpolated within the rest of the arguments; this makes + it possible to have an array of arguments and pass that array to + shellquote() instead of having to specify specify each argument + individually in the call. + ") \ + do |args| + + result = [] + args.flatten.each do |word| + if word.length != 0 and word.count(Safe) == word.length + result << word + elsif word.count(Dangerous) == 0 + result << ('"' + word + '"') + elsif word.count("'") == 0 + result << ("'" + word + "'") + else + r = '"' + word.each_byte() do |c| + if Dangerous.include?(c) + r += "\\" + end + r += c.chr() + end + r += '"' + result << r + end + end + + return result.join(" ") + end +end diff --git a/spec/unit/parser/functions/shellquote.rb b/spec/unit/parser/functions/shellquote.rb new file mode 100755 index 0000000..283a4de --- /dev/null +++ b/spec/unit/parser/functions/shellquote.rb @@ -0,0 +1,92 @@ +#! /usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "the shellquote function" do + + before :each do + @scope = Puppet::Parser::Scope.new() + end + + it "should exist" do + Puppet::Parser::Functions.function("shellquote").should == "function_shellquote" + end + + + it "should handle no arguments" do + result = @scope.function_shellquote([]) + result.should(eql("")) + end + + it "should handle several simple arguments" do + result = @scope.function_shellquote( + ['foo', '[email protected]', 'localhost:/dev/null', 'xyzzy+-4711,23']) + result.should(eql( + 'foo [email protected] localhost:/dev/null xyzzy+-4711,23')) + end + + it "should handle array arguments" do + result = @scope.function_shellquote( + ['foo', ['[email protected]', 'localhost:/dev/null'], + 'xyzzy+-4711,23']) + result.should(eql( + 'foo [email protected] localhost:/dev/null xyzzy+-4711,23')) + end + + it "should quote unsafe characters" do + result = @scope.function_shellquote( + ['/etc/passwd ', '(ls)', '*', '[?]', "'&'"]) + result.should(eql( + '"/etc/passwd " "(ls)" "*" "[?]" "\'&\'"')) + end + + it "should deal with double quotes" do + result = @scope.function_shellquote( + ['"foo"bar"']) + result.should(eql( + '\'"foo"bar"\'')) + end + + it "should cope with dollar signs" do + result = @scope.function_shellquote( + ['$PATH', 'foo$bar', '"x$"']) + result.should(eql( + "'$PATH' 'foo$bar' '\"x$\"'")) + end + + it "should deal with apostrophes (single quotes)" do + result = @scope.function_shellquote( + ["'foo'bar'", "`$'EDITOR'`"]) + result.should(eql( + '"\'foo\'bar\'" "\\`\\$\'EDITOR\'\\`"')) + end + + it "should cope with grave accents (backquotes)" do + result = @scope.function_shellquote( + ['`echo *`', '`ls "$MAILPATH"`']) + result.should(eql( + "'`echo *`' '`ls \"$MAILPATH\"`'")) + end + + it "should deal with both single and double quotes" do + result = @scope.function_shellquote( + ['\'foo"bar"xyzzy\'', '"foo\'bar\'xyzzy"']) + result.should(eql( + '"\'foo\\"bar\\"xyzzy\'" "\\"foo\'bar\'xyzzy\\""')) + end + + it "should handle multiple quotes *and* dollars and backquotes" do + result = @scope.function_shellquote( + ['\'foo"$x`bar`"xyzzy\'']) + result.should(eql( + '"\'foo\\"\\$x\\`bar\\`\\"xyzzy\'"')) + end + + it "should handle linefeeds" do + result = @scope.function_shellquote( + ["foo \n bar"]) + result.should(eql( + "\"foo \n bar\"")) + end + +end -- 1.6.0.6 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---
