From 3abeb791484c5a4747c6506fcadd4aaf6f2e2799 Mon Sep 17 00:00:00 2001 From: Stefan Karpinski Date: Fri, 30 Dec 2016 18:27:15 -0500 Subject: [PATCH] shell_parse: deprecate unescaped chars "#{}()[]<>|&*?~;" in commands --- base/managers.jl | 5 +++-- base/process.jl | 3 ++- base/shell.jl | 22 +++++++++++++++------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/base/managers.jl b/base/managers.jl index c270183c405870..8c59199c5ddcf0 100644 --- a/base/managers.jl +++ b/base/managers.jl @@ -185,7 +185,7 @@ function launch_on_machine(manager::SSHManager, machine, cnt, params, launched, cmd = `cd $dir '&&' $tval $exename $exeflags` # shell login (-l) with string command (-c) to launch julia process - cmd = `sh -l -c $(shell_escape(cmd))` + cmd = `sh -l -c $(shell_escape(cmd, special = ""))` # remote launch with ssh with given ssh flags / host / port information # -T → disable pseudo-terminal allocation @@ -195,13 +195,14 @@ function launch_on_machine(manager::SSHManager, machine, cnt, params, launched, # forwarded connections are causing collisions # -n → Redirects stdin from /dev/null (actually, prevents reading from stdin). # Used when running ssh in the background. - cmd = `ssh -T -a -x -o ClearAllForwardings=yes -n $sshflags $host $(shell_escape(cmd))` + cmd = `ssh -T -a -x -o ClearAllForwardings=yes -n $sshflags $host $(shell_escape(cmd, special = ""))` # launch the remote Julia process # detach launches the command in a new process group, allowing it to outlive # the initial julia process (Ctrl-C and teardown methods are handled through messages) # for the launched porcesses. + @show cmd io, pobj = open(pipeline(detach(cmd), stderr=STDERR), "r") wconfig = WorkerConfig() diff --git a/base/process.jl b/base/process.jl index d2d0bddd7b8dd2..c8a249d8583116 100644 --- a/base/process.jl +++ b/base/process.jl @@ -97,7 +97,8 @@ end hash(x::AndCmds, h::UInt) = hash(x.a, hash(x.b, h)) ==(x::AndCmds, y::AndCmds) = x.a == y.a && x.b == y.b -shell_escape(cmd::Cmd) = shell_escape(cmd.exec...) +shell_escape(cmd::Cmd; special::AbstractString=shell_special) = + shell_escape(cmd.exec..., special=special) function show(io::IO, cmd::Cmd) print_env = cmd.env !== nothing diff --git a/base/shell.jl b/base/shell.jl index e9aebba337d8e6..8de19ae87d5d7b 100644 --- a/base/shell.jl +++ b/base/shell.jl @@ -2,6 +2,8 @@ ## shell-like command parsing ## +const shell_special = "#{}()[]<>|&*?~;" + function shell_parse(str::AbstractString, interpolate::Bool=true) s = lstrip(str) # strips the end but respects the space when the string ends with "\\ " @@ -92,6 +94,8 @@ function shell_parse(str::AbstractString, interpolate::Bool=true) update_arg(s[i:j-1]); i = k c, k = next(s,k) end + elseif !in_single_quotes && !in_double_quotes && c in shell_special + depwarn("special characters \"$shell_special\" should now be quoted in commands", :shell_parse) end j = k end @@ -122,14 +126,14 @@ function shell_split(s::AbstractString) args end -function print_shell_word(io::IO, word::AbstractString) +function print_shell_word(io::IO, word::AbstractString, special::AbstractString = shell_special) if isempty(word) print(io, "''") end has_single = false has_special = false for c in word - if isspace(c) || c=='\\' || c=='\'' || c=='"' || c=='$' + if isspace(c) || c=='\\' || c=='\'' || c=='"' || c=='$' || c in special has_special = true if c == '\'' has_single = true @@ -152,13 +156,17 @@ function print_shell_word(io::IO, word::AbstractString) end end -function print_shell_escaped(io::IO, cmd::AbstractString, args::AbstractString...) - print_shell_word(io, cmd) +function print_shell_escaped( + io::IO, cmd::AbstractString, args::AbstractString...; + special::AbstractString=shell_special + ) + print_shell_word(io, cmd, special) for arg in args print(io, ' ') - print_shell_word(io, arg) + print_shell_word(io, arg, special) end end -print_shell_escaped(io::IO) = nothing +print_shell_escaped(io::IO; special::String=shell_special) = nothing -shell_escape(args::AbstractString...) = sprint(print_shell_escaped, args...) +shell_escape(args::AbstractString...; special::AbstractString=shell_special) = + sprint(io->print_shell_escaped(io, args..., special=special))