Browse files

Reuse shell fallback code for exec()

We had three places where we determined sh fallback or not. This unifies
this to a single place. It also makes Process.exec able to handle a
string directly and determine itself whether it needs a shell or not.

Fixes #2088
  • Loading branch information...
1 parent c3dfcb3 commit 2ea9978c159af3a54bc3442ccbe11b6869168c9b @dbussink dbussink committed Dec 11, 2012
Showing with 59 additions and 60 deletions.
  1. +1 −1 kernel/common/io18.rb
  2. +1 −1 kernel/common/io19.rb
  3. +1 −6 kernel/common/process18.rb
  4. +1 −4 kernel/common/process19.rb
  5. +55 −48 vm/builtin/system.cpp
View
2 kernel/common/io18.rb
@@ -451,7 +451,7 @@ def self.popen(str, mode="r")
return nil
end
else
- Process.perform_exec "/bin/sh", ["sh", "-c", str]
+ Process.perform_exec str, []
end
end
View
2 kernel/common/io19.rb
@@ -1068,7 +1068,7 @@ def self.popen(str, mode=undefined, options=undefined)
Process.perform_exec cmd.first, cmd.map(&:to_s)
else
- Process.perform_exec "/bin/sh", ["sh", "-c", str]
+ Process.perform_exec str, []
end
end
View
7 kernel/common/process18.rb
@@ -8,12 +8,7 @@ def self.set_status_global(status)
def self.exec(cmd, *args)
if args.empty? and cmd.kind_of? String
raise Errno::ENOENT if cmd.empty?
- if /([*?{}\[\]<>()~&|$;'`"\n])/o.match(cmd)
- Process.perform_exec "/bin/sh", ["sh", "-c", cmd]
- else
- args = cmd.split(' ')
- Process.perform_exec args.first, args
- end
+ Process.perform_exec cmd, []
else
if ary = Rubinius::Type.try_convert(cmd, Array, :to_ary)
raise ArgumentError, "wrong first argument" unless ary.size == 2
View
5 kernel/common/process19.rb
@@ -188,11 +188,8 @@ def self.adjust_argv(first, *args)
if args.empty? and cmd = Rubinius::Type.try_convert(first, String, :to_str)
if cmd.empty?
raise Errno::ENOENT
- elsif /([*?{}\[\]<>()~&|$;'`"\n])/o.match(cmd)
- return ["/bin/sh", ["sh", "-c", cmd]]
else
- args = cmd.split(' ')
- return [args.first, args]
+ return [cmd, []]
end
elsif cmd = Rubinius::Type.try_convert(first, Array, :to_ary)
raise ArgumentError, "wrong first argument" unless cmd.size == 2
View
103 vm/builtin/system.cpp
@@ -190,6 +190,54 @@ namespace rubinius {
return obj;
}
+ void exec_sh_fallback(STATE, const char* c_str, size_t c_len) {
+ char* s = const_cast<char*>(c_str);
+ bool use_sh = false;
+
+ for(;*s;s++) {
+ if(*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n\t\r\f\v",*s)) {
+ use_sh = true;
+ break;
+ }
+ }
+
+ if(use_sh) {
+ execl("/bin/sh", "sh", "-c", c_str, (char*)0);
+ } else {
+ size_t max_spaces = (c_len / 2) + 2;
+ char** args = new char*[max_spaces];
+
+ // Now put nulls for spaces into c_str and assign each bit
+ // to args to create the array of char*s that execv wants.
+
+ s = const_cast<char*>(c_str);
+ const char* s_end = c_str + c_len;
+ int idx = 0;
+
+ for(;;) {
+ // turn the next group of spaces into nulls.
+ while(s < s_end && *s == ' ') {
+ *s = 0;
+ s++;
+ }
+
+ // Hit the end, bail.
+ if(s == s_end) break;
+
+ // Write the address of the next chunk here.
+ args[idx++] = s;
+
+ // Skip to the next space
+ while(s < s_end && *s != ' ') s++;
+ }
+
+ args[idx] = 0;
+
+ // If we added anything, then exec, otherwise fall through and fail.
+ if(idx > 0) execvp(args[0], args);
+ }
+ }
+
Object* System::vm_exec(STATE, String* path, Array* args,
CallFrame* calling_environment) {
@@ -238,7 +286,12 @@ namespace rubinius {
old_handlers[i] = (void*)old_action.sa_handler;
}
- (void)::execvp(c_path, argv);
+ if(argc) {
+ (void)::execvp(c_path, argv);
+ } else {
+ exec_sh_fallback(state, c_path, path->byte_size());
+ }
+
int erno = errno;
// Hmmm, execvp failed, we need to recover here.
@@ -299,53 +352,7 @@ namespace rubinius {
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
- // detect and decide to use sh or not.
- char* s = const_cast<char*>(c_str);
- bool use_sh = false;
-
- for(;*s;s++) {
- if(*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
- use_sh = true;
- break;
- }
- }
-
- if(use_sh) {
- execl("/bin/sh", "sh", "-c", c_str, (char*)0);
- } else {
- size_t c_size = str->byte_size();
- size_t max_spaces = (c_size / 2) + 2;
- char** args = new char*[max_spaces];
-
- // Now put nulls for spaces into c_str and assign each bit
- // to args to create the array of char*s that execv wants.
-
- s = const_cast<char*>(c_str);
- const char* s_end = c_str + c_size;
- int idx = 0;
-
- for(;;) {
- // turn the next group of spaces into nulls.
- while(s < s_end && *s == ' ') {
- *s = 0;
- s++;
- }
-
- // Hit the end, bail.
- if(s == s_end) break;
-
- // Write the address of the next chunk here.
- args[idx++] = s;
-
- // Skip to the next space
- while(s < s_end && *s != ' ') s++;
- }
-
- args[idx] = 0;
-
- // If we added anything, then exec, otherwise fall through and fail.
- if(idx > 0) execvp(args[0], args);
- }
+ exec_sh_fallback(state, c_str, str->byte_size());
// bad news, shouldn't be here.
std::cerr << "execvp failed: " << strerror(errno) << std::endl;

0 comments on commit 2ea9978

Please sign in to comment.