diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-13 00:56:31 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-13 00:56:31 +0000 |
commit | 2d460925f2e5beb24fb19dc4b0a07ce1598dac60 (patch) | |
tree | 68cba742f6a4045aa1000749a58427617abf157f | |
parent | e6a6561121ef4475a0fd136524983bb22afbb3dc (diff) | |
download | ruby-2d460925f2e5beb24fb19dc4b0a07ce1598dac60.tar.gz |
process.c: use shell for reserved or special built-in
* process.c (rb_exec_fillarg): use shell if the first word is reserved
or special built-in name.
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36049 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | process.c | 80 |
2 files changed, 75 insertions, 11 deletions
@@ -1,4 +1,8 @@ -Wed Jun 13 09:55:29 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> +Wed Jun 13 09:56:29 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * process.c (rb_exec_fillarg): use shell if the first word is reserved + or special built-in name. + http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html * process.c (rb_exec_fillarg): treat '=' only in the first word. if the first word does not contain '=', it is the command name and @@ -79,6 +79,8 @@ #include <grp.h> #endif +#define numberof(array) (int)(sizeof(array)/sizeof((array)[0])) + #if defined(HAVE_TIMES) || defined(_WIN32) static VALUE rb_cProcessTms; #endif @@ -1824,6 +1826,20 @@ rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, V return prog; } +struct string_part { + const char *ptr; + size_t len; +}; + +static int +compare_posix_sh(const void *key, const void *el) +{ + const struct string_part *word = key; + int ret = strncmp(word->ptr, el, word->len); + if (!ret && ((const char *)el)[word->len]) ret = -1; + return ret; +} + static void rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, struct rb_exec_arg *e) { @@ -1850,10 +1866,40 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, str #ifndef _WIN32 if (e->use_shell) { + static const char posix_sh_cmds[][8] = { + "!", /* reserved */ + ".", /* special built-in */ + "break", /* special built-in */ + "case", /* reserved */ + "colon", /* special built-in */ + "continue", /* special built-in */ + "do", /* reserved */ + "done", /* reserved */ + "elif", /* reserved */ + "else", /* reserved */ + "esac", /* reserved */ + "eval", /* special built-in */ + "exec", /* special built-in */ + "exit", /* special built-in */ + "export", /* special built-in */ + "fi", /* reserved */ + "for", /* reserved */ + "if", /* reserved */ + "in", /* reserved */ + "readonly", /* special built-in */ + "return", /* special built-in */ + "set", /* special built-in */ + "shift", /* special built-in */ + "then", /* reserved */ + "times", /* special built-in */ + "trap", /* special built-in */ + "unset", /* special built-in */ + "until", /* reserved */ + "while", /* reserved */ + }; const char *p; - int first = 1; + struct string_part first = {0, 0}; int has_meta = 0; - int has_nonspace = 0; /* * meta characters: * @@ -1879,18 +1925,32 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, str * % (used in Parameter Expansion) */ for (p = RSTRING_PTR(prog); *p; p++) { - if (!has_nonspace && *p != ' ' && *p != '\t') - has_nonspace = 1; - if (has_nonspace && (*p == ' ' || *p == '\t')) - first = 0; + if (*p == ' ' || *p == '\t') { + if (first.ptr && !first.len) first.len = p - first.ptr; + } + else { + if (!first.ptr) first.ptr = p; + } if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p)) has_meta = 1; - if (first && *p == '=') - has_meta = 1; - if (has_nonspace && has_meta) + if (!first.len) { + if (*p == '=') { + has_meta = 1; + } + else if (*p == '/') { + first.len = SIZE_T_MAX; /* longer than any posix_sh_cmds */ + } + } + if (has_meta) break; } - if (has_nonspace && !has_meta) { + if (!has_meta && first.ptr) { + if (!first.len) first.len = p - first.ptr; + if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) && + bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh)) + has_meta = 1; + } + if (!has_meta) { /* avoid shell since no shell meta charactor found. */ e->use_shell = 0; } |