* configure.in: check functions, fork spawnv.

* io.c (rb_io_s_popen): accept argv not only single command line.

* process.c (rb_proc_exec_n): export.

* process.c (rb_check_argv): check if arguments are safe to invoke.

* process.c (rb_fork): retry to fork.

* process.c (rb_spawn): spawn child process asynchronously.

* process.c (rb_f_system): raise an exception if the command could not
  execute.

* win32/win32.c (rb_w32_argv_size): count necessary size for joined
  arguments.

* win32/win32.c (rb_w32_join_argv): join arguments with quoting.

* win32/win32.c (rb_w32_pipe_exec, rb_w32_spawn, rb_w32_aspawn):
  accept program name adding to command line.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5725 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2004-02-16 06:45:32 +00:00
Родитель 3bc0f22fce
Коммит 03d8c88b87
7 изменённых файлов: 563 добавлений и 407 удалений

Просмотреть файл

@ -1,3 +1,28 @@
Mon Feb 16 15:45:22 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in: check functions, fork spawnv.
* io.c (rb_io_s_popen): accept argv not only single command line.
* process.c (rb_proc_exec_n): export.
* process.c (rb_check_argv): check if arguments are safe to invoke.
* process.c (rb_fork): retry to fork.
* process.c (rb_spawn): spawn child process asynchronously.
* process.c (rb_f_system): raise an exception if the command could not
execute.
* win32/win32.c (rb_w32_argv_size): count necessary size for joined
arguments.
* win32/win32.c (rb_w32_join_argv): join arguments with quoting.
* win32/win32.c (rb_w32_pipe_exec, rb_w32_spawn, rb_w32_aspawn):
accept program name adding to command line.
Mon Feb 16 15:18:33 2004 Minero Aoki <aamine@loveruby.net> Mon Feb 16 15:18:33 2004 Minero Aoki <aamine@loveruby.net>
* lib/racc/parser.rb: add note for Racc full package. * lib/racc/parser.rb: add note for Racc full package.

Просмотреть файл

@ -392,7 +392,7 @@ AC_CHECK_FUNCS(ftello)
AC_REPLACE_FUNCS(dup2 memmove mkdir strcasecmp strncasecmp strerror strftime\ AC_REPLACE_FUNCS(dup2 memmove mkdir strcasecmp strncasecmp strerror strftime\
strchr strstr strtoul crypt flock vsnprintf\ strchr strstr strtoul crypt flock vsnprintf\
isnan finite isinf hypot acosh erf) isnan finite isinf hypot acosh erf)
AC_CHECK_FUNCS(fmod killpg wait4 waitpid syscall chroot fsync getcwd\ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot fsync getcwd\
truncate chsize times utimes fcntl lockf lstat link symlink readlink\ truncate chsize times utimes fcntl lockf lstat link symlink readlink\
setitimer setruid seteuid setreuid setresuid setproctitle\ setitimer setruid seteuid setreuid setresuid setproctitle\
setrgid setegid setregid setresgid issetugid pause lchown lchmod\ setrgid setegid setregid setresgid issetugid pause lchown lchmod\

Просмотреть файл

@ -12,6 +12,9 @@
**********************************************************************/ **********************************************************************/
#ifndef RUBY_INTERN_H
#define RUBY_INTERN_H 1
/* /*
* Functions and variables that are used by more than one source file of * Functions and variables that are used by more than one source file of
* the kernel. * the kernel.
@ -335,10 +338,20 @@ VALUE rb_lastline_get _((void));
void rb_lastline_set _((VALUE)); void rb_lastline_set _((VALUE));
VALUE rb_sym_all_symbols _((void)); VALUE rb_sym_all_symbols _((void));
/* process.c */ /* process.c */
struct rb_exec_arg {
int argc;
VALUE *argv;
const char *prog;
};
int rb_proc_exec_n _((int, VALUE*, const char*));
int rb_proc_exec _((const char*)); int rb_proc_exec _((const char*));
VALUE rb_check_argv _((int, VALUE*));
int rb_exec _((const struct rb_exec_arg*));
int rb_fork _((int*, int (*)_((void*)), void*));
VALUE rb_f_exec _((int,VALUE*)); VALUE rb_f_exec _((int,VALUE*));
int rb_waitpid _((int,int*,int)); int rb_waitpid _((int,int*,int));
void rb_syswait _((int)); void rb_syswait _((int));
int rb_spawn _((int, VALUE*));
VALUE rb_proc_times _((VALUE)); VALUE rb_proc_times _((VALUE));
VALUE rb_detach_process _((int)); VALUE rb_detach_process _((int));
/* range.c */ /* range.c */
@ -486,3 +499,5 @@ VALUE rb_mod_remove_cvar _((VALUE, VALUE));
/* version.c */ /* version.c */
void ruby_show_version _((void)); void ruby_show_version _((void));
void ruby_show_copyright _((void)); void ruby_show_copyright _((void));
#endif /* RUBY_INTERN_H */

330
io.c
Просмотреть файл

@ -2448,7 +2448,7 @@ rb_file_sysopen(fname, flags, mode)
return rb_file_sysopen_internal(io_alloc(rb_cFile), fname, flags, mode); return rb_file_sysopen_internal(io_alloc(rb_cFile), fname, flags, mode);
} }
#if defined (_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__VMS) #if defined(__CYGWIN__) || !defined(HAVE_FORK)
static struct pipe_list { static struct pipe_list {
OpenFile *fptr; OpenFile *fptr;
struct pipe_list *next; struct pipe_list *next;
@ -2510,7 +2510,7 @@ pipe_finalize(fptr, noraise)
OpenFile *fptr; OpenFile *fptr;
int noraise; int noraise;
{ {
#if !defined (__CYGWIN__) && !defined(_WIN32) #if !defined(HAVE_FORK) && !defined(_WIN32)
extern VALUE rb_last_status; extern VALUE rb_last_status;
int status; int status;
if (fptr->f) { if (fptr->f) {
@ -2545,152 +2545,178 @@ rb_io_unbuffered(fptr)
rb_io_synchronized(fptr); rb_io_synchronized(fptr);
} }
struct popen_arg {
struct rb_exec_arg exec;
int pr[2], pw[2];
};
static void
popen_redirect(p)
struct popen_arg *p;
{
if (p->pr[1] != -1) {
close(p->pr[0]);
if (p->pr[1] != 1) {
dup2(p->pr[1], 1);
close(p->pr[1]);
}
}
if (p->pw[0] != -1) {
close(p->pw[1]);
if (p->pw[0] != 0) {
dup2(p->pw[0], 0);
close(p->pw[0]);
}
}
}
#ifdef HAVE_FORK
static int
popen_exec(p)
struct popen_arg *p;
{
int fd;
popen_redirect(p);
for (fd = 3; fd < NOFILE; fd++) {
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFL, FD_CLOEXEC);
#else
close(fd);
#endif
}
return rb_exec(&p->exec);
}
#endif
static VALUE static VALUE
pipe_open(pname, mode) pipe_open(argc, argv, pname, mode)
int argc;
VALUE *argv;
char *pname, *mode; char *pname, *mode;
{ {
int modef = rb_io_mode_flags(mode); int modef = rb_io_mode_flags(mode);
int pid = 0;
OpenFile *fptr; OpenFile *fptr;
#if defined(DJGPP) || defined(__human68k__) || defined(__VMS)
FILE *f = popen(pname, mode);
if (!f) rb_sys_fail(pname);
else {
VALUE port = io_alloc(rb_cIO);
MakeOpenFile(port, fptr);
fptr->finalize = pipe_finalize;
fptr->mode = modef;
pipe_add_fptr(fptr);
if (modef & FMODE_READABLE) fptr->f = f;
if (modef & FMODE_WRITABLE) {
if (fptr->f) fptr->f2 = f;
else fptr->f = f;
rb_io_synchronized(fptr);
}
return (VALUE)port;
}
#else
#ifdef _WIN32
int pid;
FILE *fpr, *fpw; FILE *fpr, *fpw;
VALUE port, arg0;
retry: #if defined(HAVE_FORK)
pid = pipe_exec(pname, rb_io_mode_modenum(mode), &fpr, &fpw); int status;
if (pid == -1) { /* exec failed */ struct popen_arg arg;
if (errno == EAGAIN) {
rb_thread_sleep(1);
goto retry;
}
rb_sys_fail(pname);
}
else {
VALUE port = io_alloc(rb_cIO);
MakeOpenFile(port, fptr);
fptr->mode = modef;
fptr->mode |= FMODE_SYNC;
fptr->pid = pid;
if (modef & FMODE_READABLE) {
fptr->f = fpr;
}
if (modef & FMODE_WRITABLE) {
if (fptr->f) fptr->f2 = fpw;
else fptr->f = fpw;
}
fptr->finalize = pipe_finalize;
pipe_add_fptr(fptr);
return (VALUE)port;
}
#else
int pid, pr[2], pw[2];
volatile int doexec; volatile int doexec;
#elif defined(_WIN32)
int openmode = rb_io_mode_modenum(mode);
char *cmd = pname, *prog = NULL;
#endif
if (((modef & FMODE_READABLE) && pipe(pr) == -1) || if (!pname) {
((modef & FMODE_WRITABLE) && pipe(pw) == -1)) arg0 = rb_check_argv(argc, argv);
rb_sys_fail(pname); if (arg0) pname = StringValuePtr(arg0);
}
doexec = (strcmp("-", pname) != 0); #if defined(HAVE_FORK)
doexec = (argc > 0) || (strcmp("-", pname) != 0);
if (!doexec) { if (!doexec) {
fflush(stdin); /* is it really needed? */ fflush(stdin); /* is it really needed? */
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
} }
arg.pr[0] = arg.pr[1] = arg.pw[0] = arg.pw[1] = -1;
retry: if ((modef & FMODE_READABLE) && pipe(arg.pr) == -1) {
switch ((pid = fork())) {
case 0: /* child */
if (modef & FMODE_READABLE) {
close(pr[0]);
if (pr[1] != 1) {
dup2(pr[1], 1);
close(pr[1]);
}
}
if (modef & FMODE_WRITABLE) {
close(pw[1]);
if (pw[0] != 0) {
dup2(pw[0], 0);
close(pw[0]);
}
}
if (doexec) {
int fd;
for (fd = 3; fd < NOFILE; fd++)
close(fd);
rb_proc_exec(pname);
fprintf(stderr, "%s:%d: command not found: %s\n",
ruby_sourcefile, ruby_sourceline, pname);
_exit(127);
}
rb_io_synchronized(RFILE(orig_stdout)->fptr);
rb_io_synchronized(RFILE(orig_stderr)->fptr);
return Qnil;
case -1: /* fork failed */
if (errno == EAGAIN) {
rb_thread_sleep(1);
goto retry;
}
close(pr[0]); close(pw[1]);
rb_sys_fail(pname); rb_sys_fail(pname);
break; }
if ((modef & FMODE_WRITABLE) && pipe(arg.pw) == -1) {
if (modef & FMODE_READABLE) {
int e = errno;
close(arg.pr[0]); close(arg.pr[1]);
errno = e;
}
rb_sys_fail(pname);
}
default: /* parent */ if (doexec) {
if (pid < 0) rb_sys_fail(pname); arg.exec.argc = argc;
else { arg.exec.argv = argv;
VALUE port = io_alloc(rb_cIO); arg.exec.prog = pname;
pid = rb_fork(&status, popen_exec, &arg);
MakeOpenFile(port, fptr); }
fptr->mode = modef; else {
fptr->mode |= FMODE_SYNC; pid = rb_fork(&status, 0, 0);
fptr->pid = pid; if (pid == 0) { /* child */
popen_redirect(&arg);
if (modef & FMODE_READABLE) { rb_io_synchronized(RFILE(orig_stdout)->fptr);
close(pr[1]); rb_io_synchronized(RFILE(orig_stderr)->fptr);
fptr->f = rb_fdopen(pr[0], "r"); return Qnil;
}
if (modef & FMODE_WRITABLE) {
FILE *f = rb_fdopen(pw[1], "w");
close(pw[0]);
if (fptr->f) fptr->f2 = f;
else fptr->f = f;
}
#if defined (__CYGWIN__)
fptr->finalize = pipe_finalize;
pipe_add_fptr(fptr);
#endif
return port;
} }
} }
/* parent */
if (modef & FMODE_READABLE) close(arg.pr[1]);
if (modef & FMODE_WRITABLE) close(arg.pw[0]);
if (pid == -1) {
if (modef & FMODE_READABLE) close(arg.pr[0]);
if (modef & FMODE_WRITABLE) close(arg.pw[1]);
rb_sys_fail(pname);
}
#define PIPE_FDOPEN(i) (rb_fdopen((i?arg.pw:arg.pr)[i], i?"w":"r"))
#elif defined(_WIN32)
if (argc) {
char **args = ALLOC_N(char *, argc+1);
int i;
for (i = 0; i < argc; ++i) {
args[i] = RSTRING(argv[i])->ptr;
}
args[i] = NULL;
cmd = ALLOCA_N(char, rb_w32_argv_size(args));
rb_w32_join_argv(cmd, args);
free(args);
prog = pname;
}
while ((pid = rb_w32_pipe_exec(cmd, prog, openmode, &fpr, &fpw)) == -1) {
/* exec failed */
switch (errno) {
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif #endif
rb_thread_sleep(1);
break;
defined:
rb_sys_fail(pname);
break;
}
}
#define PIPE_FDOPEN(i) (i?fpw:fpr)
#else
if (argc > 0) {
prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
pname = StringValuePtr(prog);
}
fpr = popen(pname, mode);
if (!fpr) rb_sys_fail(pname);
#define PIPE_FDOPEN(i) (fpr)
#endif #endif
port = io_alloc(rb_cIO);
MakeOpenFile(port, fptr);
fptr->mode = modef | FMODE_SYNC;
fptr->pid = pid;
if (modef & FMODE_READABLE) {
fptr->f = PIPE_FDOPEN(0);
}
if (modef & FMODE_WRITABLE) {
fpw = PIPE_FDOPEN(1);
if (fptr->f) fptr->f2 = fpw;
else fptr->f = fpw;
}
#if defined (__CYGWIN__) || !defined(HAVE_FORK)
fptr->finalize = pipe_finalize;
pipe_add_fptr(fptr);
#endif
return port;
} }
static VALUE static VALUE
@ -2714,7 +2740,7 @@ rb_io_popen(str, argc, argv, klass)
mode = StringValuePtr(pmode); mode = StringValuePtr(pmode);
} }
SafeStringValue(pname); SafeStringValue(pname);
port = pipe_open(str, mode); port = pipe_open(0, 0, str, mode);
if (NIL_P(port)) { if (NIL_P(port)) {
/* child */ /* child */
if (rb_block_given_p()) { if (rb_block_given_p()) {
@ -2779,12 +2805,46 @@ rb_io_s_popen(argc, argv, klass)
VALUE *argv; VALUE *argv;
VALUE klass; VALUE klass;
{ {
char *str = 0; char *mode;
VALUE pname, pmode, port, tmp;
char mbuf[4];
if (argc >= 1) { if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
str = StringValuePtr(argv[0]); mode = "r";
} }
return rb_io_popen(str, argc, argv, klass); else if (FIXNUM_P(pmode)) {
mode = rb_io_modenum_mode(FIX2INT(pmode), mbuf);
}
else {
mode = StringValuePtr(pmode);
}
tmp = rb_check_array_type(pname);
if (!NIL_P(tmp)) {
long argc = RARRAY(tmp)->len;
VALUE *argv = ALLOCA_N(VALUE, argc);
MEMCPY(argv, RARRAY(tmp)->ptr, VALUE, argc);
port = pipe_open(argc, argv, 0, mode);
}
else {
SafeStringValue(pname);
port = pipe_open(0, 0, RSTRING(pname)->ptr, mode);
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {
rb_yield(Qnil);
fflush(stdout);
fflush(stderr);
_exit(0);
}
return Qnil;
}
}
RBASIC(port)->klass = klass;
if (rb_block_given_p()) {
return rb_ensure(rb_yield, port, io_close, port);
}
return port;
} }
static VALUE static VALUE
@ -2985,7 +3045,7 @@ rb_io_open(fname, mode)
char *fname, *mode; char *fname, *mode;
{ {
if (fname[0] == '|') { if (fname[0] == '|') {
return pipe_open(fname+1, mode); return pipe_open(0, 0, fname+1, mode);
} }
else { else {
return rb_file_open(fname, mode); return rb_file_open(fname, mode);
@ -4179,7 +4239,7 @@ rb_f_backquote(obj, str)
OpenFile *fptr; OpenFile *fptr;
SafeStringValue(str); SafeStringValue(str);
port = pipe_open(RSTRING(str)->ptr, "r"); port = pipe_open(0, 0, RSTRING(str)->ptr, "r");
if (NIL_P(port)) return rb_str_new(0,0); if (NIL_P(port)) return rb_str_new(0,0);
GetOpenFile(port, fptr); GetOpenFile(port, fptr);

420
process.c
Просмотреть файл

@ -23,6 +23,9 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef __DJGPP__ #ifdef __DJGPP__
#include <process.h> #include <process.h>
#endif #endif
@ -912,12 +915,16 @@ proc_exec_v(argv, prog)
char **argv; char **argv;
char *prog; char *prog;
{ {
int err;
if (!prog) if (!prog)
prog = argv[0]; prog = argv[0];
security(prog); security(prog);
prog = dln_find_exe(prog, 0); prog = dln_find_exe(prog, 0);
if (!prog) if (!prog) {
errno = ENOENT;
return -1; return -1;
}
#if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__) || defined(__EMX__) || defined(OS2) #if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__) || defined(__EMX__) || defined(OS2)
{ {
@ -958,26 +965,23 @@ proc_exec_v(argv, prog)
#endif /* MSDOS or __human68k__ or __EMX__ */ #endif /* MSDOS or __human68k__ or __EMX__ */
before_exec(); before_exec();
execv(prog, argv); execv(prog, argv);
err = errno;
after_exec(); after_exec();
errno = err;
return -1; return -1;
} }
static int int
proc_exec_n(argc, argv, progv) rb_proc_exec_n(argc, argv, prog)
int argc; int argc;
VALUE *argv; VALUE *argv;
VALUE progv; const char *prog;
{ {
char *prog = 0;
char **args; char **args;
int i; int i;
if (progv) {
prog = RSTRING(progv)->ptr;
}
args = ALLOCA_N(char*, argc+1); args = ALLOCA_N(char*, argc+1);
for (i=0; i<argc; i++) { for (i=0; i<argc; i++) {
SafeStringValue(argv[i]);
args[i] = RSTRING(argv[i])->ptr; args[i] = RSTRING(argv[i])->ptr;
} }
args[i] = 0; args[i] = 0;
@ -1000,22 +1004,21 @@ rb_proc_exec(str)
#ifdef _WIN32 #ifdef _WIN32
before_exec(); before_exec();
do_spawn(P_OVERLAY, (char *)str); rb_w32_spawn(P_OVERLAY, (char *)str, 0);
after_exec(); after_exec();
#else #else
for (s=str; *s; s++) { for (s=str; *s; s++) {
if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
#if defined(MSDOS)
int status; int status;
#if defined(MSDOS)
before_exec(); before_exec();
status = system(str); status = system(str);
after_exec(); after_exec();
if (status != -1) if (status != -1)
exit(status); exit(status);
#else #elif defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
#if defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
char *shell = dln_find_exe("sh", 0); char *shell = dln_find_exe("sh", 0);
int status = -1; status = -1;
before_exec(); before_exec();
if (shell) if (shell)
execl(shell, "sh", "-c", str, (char *) NULL); execl(shell, "sh", "-c", str, (char *) NULL);
@ -1027,8 +1030,9 @@ rb_proc_exec(str)
#else #else
before_exec(); before_exec();
execl("/bin/sh", "sh", "-c", str, (char *)NULL); execl("/bin/sh", "sh", "-c", str, (char *)NULL);
status = errno;
after_exec(); after_exec();
#endif errno = status;
#endif #endif
return -1; return -1;
} }
@ -1050,12 +1054,20 @@ rb_proc_exec(str)
return -1; return -1;
} }
#if defined(__human68k__) || defined(__DJGPP__) || defined(_WIN32) #if defined(_WIN32)
#define HAVE_SPAWNV 1
#endif
#if !defined(HAVE_FORK) && defined(HAVE_SPAWNV)
static int static int
proc_spawn_v(argv, prog) proc_spawn_v(argv, prog)
char **argv; char **argv;
char *prog; char *prog;
{ {
#if defined(_WIN32)
char *cmd = ALLOCA_N(char, rb_w32_argv_size(argv));
return rb_w32_spawn(P_NOWAIT, rb_w32_join_argv(cmd, argv), prog);
#else
char *extension; char *extension;
int status; int status;
@ -1091,13 +1103,10 @@ proc_spawn_v(argv, prog)
} }
#endif #endif
before_exec(); before_exec();
#if defined(_WIN32)
status = do_aspawn(P_WAIT, prog, argv);
#else
status = spawnv(P_WAIT, prog, argv); status = spawnv(P_WAIT, prog, argv);
#endif
after_exec(); after_exec();
return status; return status;
#endif
} }
static int static int
@ -1111,29 +1120,25 @@ proc_spawn_n(argc, argv, prog)
args = ALLOCA_N(char*, argc + 1); args = ALLOCA_N(char*, argc + 1);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
SafeStringValue(argv[i]);
args[i] = RSTRING(argv[i])->ptr; args[i] = RSTRING(argv[i])->ptr;
} }
if (prog)
SafeStringValue(prog);
args[i] = (char*) 0; args[i] = (char*) 0;
if (args[0]) if (args[0])
return proc_spawn_v(args, prog ? RSTRING(prog)->ptr : 0); return proc_spawn_v(args, prog ? RSTRING(prog)->ptr : 0);
return -1; return -1;
} }
#if !defined(_WIN32) #if defined(_WIN32)
#define proc_spawn(str) rb_w32_spawn(P_NOWAIT, str, 0)
#else
static int static int
proc_spawn(sv) proc_spawn(str)
VALUE sv;
{
char *str; char *str;
{
char *s, *t; char *s, *t;
char **argv, **a; char **argv, **a;
int status; int status;
SafeStringValue(sv);
str = s = RSTRING(sv)->ptr;
for (s = str; *s; s++) { for (s = str; *s; s++) {
if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
char *shell = dln_find_exe("sh", 0); char *shell = dln_find_exe("sh", 0);
@ -1156,6 +1161,35 @@ proc_spawn(sv)
#endif #endif
#endif #endif
VALUE
rb_check_argv(argc, argv)
int argc;
VALUE *argv;
{
VALUE tmp, prog;
int i;
if (argc == 0) {
rb_raise(rb_eArgError, "wrong number of arguments");
}
prog = 0;
tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
if (RARRAY(tmp)->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
prog = RARRAY(tmp)->ptr[0];
SafeStringValue(prog);
argv[0] = RARRAY(tmp)->ptr[1];
}
for (i = 0; i < argc; i++) {
SafeStringValue(argv[i]);
}
security(RSTRING(prog ? prog : argv[0])->ptr);
return prog;
}
/* /*
* call-seq: * call-seq:
* exec(command [, arg, ...]) * exec(command [, arg, ...])
@ -1186,35 +1220,116 @@ rb_f_exec(argc, argv)
int argc; int argc;
VALUE *argv; VALUE *argv;
{ {
VALUE prog = 0; struct rb_exec_arg e;
VALUE tmp; VALUE prog;
if (argc == 0) { prog = rb_check_argv(argc, argv);
rb_raise(rb_eArgError, "wrong number of arguments"); if (!prog && argc == 1) {
} --argc;
prog = *argv++;
tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
if (RARRAY(tmp)->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
prog = RARRAY(tmp)->ptr[0];
SafeStringValue(prog);
argv[0] = RARRAY(tmp)->ptr[1];
}
if (argc == 1 && prog == 0) {
VALUE cmd = argv[0];
SafeStringValue(cmd);
rb_proc_exec(RSTRING(cmd)->ptr);
}
else {
proc_exec_n(argc, argv, prog);
} }
e.argc = argc;
e.argv = argv;
e.prog = prog ? RSTRING(prog)->ptr : 0;
rb_exec(&e);
rb_sys_fail(RSTRING(argv[0])->ptr); rb_sys_fail(RSTRING(argv[0])->ptr);
return Qnil; /* dummy */ return Qnil; /* dummy */
} }
int
rb_exec(e)
const struct rb_exec_arg *e;
{
int argc = e->argc;
VALUE *argv = e->argv;
const char *prog = e->prog;
if (argc == 0) {
rb_proc_exec(prog);
}
else {
rb_proc_exec_n(argc, argv, prog);
}
return errno;
}
#ifdef HAVE_FORK
int
rb_fork(status, chfunc, charg)
int *status;
int (*chfunc) _((void *));
void *charg;
{
int pid, err, state = 0, ep[2];
#ifndef __VMS
fflush(stdout);
fflush(stderr);
#endif
#ifdef FD_CLOEXEC
if (chfunc) {
if (pipe(ep)) return -1;
if (fcntl(ep[0], F_SETFD, FD_CLOEXEC) ||
fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
err = errno;
close(ep[0]);
close(ep[1]);
errno = err;
return -1;
}
}
#endif
while ((pid = fork()) < 0) {
switch (errno) {
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
if (!status && !chfunc) {
rb_thread_sleep(1);
continue;
}
else {
rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
if (status) *status = state;
if (!state) continue;
}
default:
#ifdef FD_CLOEXEC
if (chfunc) {
err = errno;
close(ep[0]);
close(ep[1]);
errno = err;
}
#endif
if (state && !status) rb_jump_tag(state);
return -1;
}
}
if (!pid) {
if (chfunc) {
err = (*chfunc)(charg);
write(ep[1], &err, sizeof(err));
_exit(127);
}
}
else if (chfunc) {
close(ep[1]);
if ((state = read(ep[0], &err, sizeof(err))) < 0) {
err = errno;
}
close(ep[0]);
if (state) {
rb_syswait(pid);
errno = err;
return -1;
}
}
return pid;
}
#endif
/* /*
* call-seq: * call-seq:
@ -1227,11 +1342,12 @@ static VALUE
rb_f_fork(obj) rb_f_fork(obj)
VALUE obj; VALUE obj;
{ {
#if !defined(__human68k__) && !defined(_WIN32) && !defined(__MACOS__) && !defined(__EMX__) && !defined(__VMS) #ifdef HAVE_FORK
int pid; int pid;
rb_secure(2); rb_secure(2);
switch (pid = fork()) {
switch (pid = rb_fork(0, 0, 0)) {
case 0: case 0:
#ifdef linux #ifdef linux
after_exec(); after_exec();
@ -1337,6 +1453,48 @@ rb_syswait(pid)
} }
} }
int
rb_spawn(argc, argv)
int argc;
VALUE *argv;
{
int status;
VALUE prog;
#if defined HAVE_FORK
int pid;
struct rb_exec_arg earg;
#endif
prog = rb_check_argv(argc, argv);
if (!prog && argc == 1) {
--argc;
prog = *argv++;
}
#if defined HAVE_FORK
earg.argc = argc;
earg.argv = argv;
earg.prog = prog ? RSTRING(prog)->ptr : 0;
status = rb_fork(&status, (int (*)_((void*)))rb_exec, &earg);
#elif defined HAVE_SPAWNV
if (!argc) {
status = proc_spawn(RSTRING(prog)->ptr);
}
else {
status = proc_spawn_n(argc, argv, prog);
}
#else
prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
status = system(StringValuePtr(prog));
# if defined(__human68k__) || defined(__DJGPP__)
last_status_set(status == -1 ? 127 : status, 0);
# else
last_status_set((status & 0xff) << 8, 0);
# endif
#endif
return status;
}
/* /*
* call-seq: * call-seq:
* system(cmd [, arg, ...]) => true or false * system(cmd [, arg, ...]) => true or false
@ -1362,137 +1520,41 @@ rb_f_system(argc, argv)
VALUE *argv; VALUE *argv;
{ {
int status; int status;
#if defined(__EMX__)
VALUE cmd;
fflush(stdout);
fflush(stderr);
if (argc == 0) {
rb_last_status = Qnil;
rb_raise(rb_eArgError, "wrong number of arguments");
}
if (TYPE(argv[0]) == T_ARRAY) {
if (RARRAY(argv[0])->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
argv[0] = RARRAY(argv[0])->ptr[0];
}
cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
SafeStringValue(cmd);
status = do_spawn(RSTRING(cmd)->ptr);
last_status_set(status, 0);
#elif defined(__human68k__) || defined(__DJGPP__) || defined(_WIN32)
volatile VALUE prog = 0;
fflush(stdout);
fflush(stderr);
if (argc == 0) {
rb_last_status = Qnil;
rb_raise(rb_eArgError, "wrong number of arguments");
}
if (TYPE(argv[0]) == T_ARRAY) {
if (RARRAY(argv[0])->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
prog = RARRAY(argv[0])->ptr[0];
argv[0] = RARRAY(argv[0])->ptr[1];
}
if (argc == 1 && prog == 0) {
#if defined(_WIN32)
SafeStringValue(argv[0]);
status = do_spawn(P_WAIT, RSTRING(argv[0])->ptr);
#else
status = proc_spawn(argv[0]);
#endif
}
else {
status = proc_spawn_n(argc, argv, prog);
}
#if defined(_WIN32)
last_status_set(status, 0);
#else
last_status_set(status == -1 ? 127 : status, 0);
#endif
#elif defined(__VMS)
VALUE cmd;
if (argc == 0) {
rb_last_status = Qnil;
rb_raise(rb_eArgError, "wrong number of arguments");
}
if (TYPE(argv[0]) == T_ARRAY) {
if (RARRAY(argv[0])->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
argv[0] = RARRAY(argv[0])->ptr[0];
}
cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
SafeStringValue(cmd);
status = system(RSTRING(cmd)->ptr);
last_status_set((status & 0xff) << 8, 0);
#else
volatile VALUE prog = 0;
int pid;
int i;
fflush(stdout);
fflush(stderr);
if (argc == 0) {
rb_last_status = Qnil;
rb_raise(rb_eArgError, "wrong number of arguments");
}
if (TYPE(argv[0]) == T_ARRAY) {
if (RARRAY(argv[0])->len != 2) {
rb_raise(rb_eArgError, "wrong first argument");
}
prog = RARRAY(argv[0])->ptr[0];
argv[0] = RARRAY(argv[0])->ptr[1];
}
if (prog) {
SafeStringValue(prog);
}
for (i = 0; i < argc; i++) {
SafeStringValue(argv[i]);
}
retry:
switch (pid = fork()) {
case 0:
if (argc == 1 && prog == 0) {
rb_proc_exec(RSTRING(argv[0])->ptr);
}
else {
proc_exec_n(argc, argv, prog);
}
_exit(127);
break; /* not reached */
case -1:
if (errno == EAGAIN) {
rb_thread_sleep(1);
goto retry;
}
rb_sys_fail(0);
break;
default:
rb_syswait(pid);
}
status = rb_spawn(argc, argv);
if (status == -1) rb_sys_fail(RSTRING(argv[0])->ptr);
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
rb_syswait(status);
status = NUM2INT(rb_last_status); status = NUM2INT(rb_last_status);
#endif #endif
if (status == EXIT_SUCCESS) return Qtrue; if (status == EXIT_SUCCESS) return Qtrue;
return Qfalse; return Qfalse;
} }
/*
* call-seq:
* spawn(cmd [, arg, ...]) => pid
*
* Similar to <code>Kernel::system</code> except for not waiting for
* end of _cmd_, but returns its <i>pid</i>.
*/
static VALUE
rb_f_spawn(argc, argv)
int argc;
VALUE *argv;
{
int pid;
pid = rb_spawn(argc, argv);
if (pid == -1) rb_sys_fail(RSTRING(argv[0])->ptr);
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
return INT2NUM(pid);
#else
return Qnil;
#endif
}
/* /*
* call-seq: * call-seq:
* sleep(duration=0) => fixnum * sleep(duration=0) => fixnum
@ -3314,6 +3376,7 @@ Init_process()
rb_define_global_function("fork", rb_f_fork, 0); rb_define_global_function("fork", rb_f_fork, 0);
rb_define_global_function("exit!", rb_f_exit_bang, -1); rb_define_global_function("exit!", rb_f_exit_bang, -1);
rb_define_global_function("system", rb_f_system, -1); rb_define_global_function("system", rb_f_system, -1);
rb_define_global_function("spawn", rb_f_spawn, -1);
rb_define_global_function("sleep", rb_f_sleep, -1); rb_define_global_function("sleep", rb_f_sleep, -1);
rb_mProcess = rb_define_module("Process"); rb_mProcess = rb_define_module("Process");
@ -3332,6 +3395,7 @@ Init_process()
#endif #endif
rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0); rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1); rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1); /* in eval.c */ rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1); /* in eval.c */
rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1); /* in eval.c */ rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1); /* in eval.c */

Просмотреть файл

@ -589,8 +589,79 @@ rb_w32_get_osfhandle(int fh)
return _get_osfhandle(fh); return _get_osfhandle(fh);
} }
int
rb_w32_argv_size(argv)
char **argv;
{
char *p, **t;
int len, n, bs, quote;
for (t = argv, len = 0; *t; t++) {
for (p = *t, n = quote = bs = 0; *p; ++p) {
switch (*p) {
case '\\':
++bs;
break;
case '"':
n += bs + 1; bs = 0;
quote = 1;
break;
case ' ': case '\t':
quote = 1;
default:
bs = 0;
p = CharNext(p) - 1;
break;
}
}
len += p - *t + n + 1;
if (quote) len += 2;
}
return len;
}
char *
rb_w32_join_argv(cmd, argv)
char *cmd;
char **argv;
{
char *p, *q, *s, **t;
int n, bs, quote;
for (t = argv, q = cmd; p = *t; t++) {
quote = 0;
s = p;
if (!*p || strpbrk(p, " \t\"")) {
quote = 1;
*q++ = '"';
}
for (bs = 0; *p; ++p) {
switch (*p) {
case '\\':
++bs;
break;
case '"':
memcpy(q, s, n = p - s); q += n; s = p;
memset(q, '\\', ++bs); q += bs; bs = 0;
break;
default:
bs = 0;
p = CharNext(p) - 1;
break;
}
}
memcpy(q, s, n = p - s);
q += n;
if (quote) *q++ = '"';
*q++ = ' ';
}
if (q > cmd) --q;
*q = '\0';
return cmd;
}
pid_t pid_t
pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw) rb_w32_pipe_exec(char *cmd, char *prog, int mode, FILE **fpr, FILE **fpw)
{ {
struct ChildRecord* child; struct ChildRecord* child;
HANDLE hReadIn, hReadOut; HANDLE hReadIn, hReadOut;
@ -667,7 +738,7 @@ pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
CloseHandle(hCurProc); CloseHandle(hCurProc);
/* create child process */ /* create child process */
child = CreateChild(cmd, NULL, &sa, hWriteIn, hReadOut, NULL); child = CreateChild(cmd, prog, &sa, hWriteIn, hReadOut, NULL);
if (!child) { if (!child) {
if (reading) { if (reading) {
CloseHandle(hReadOut); CloseHandle(hReadOut);
@ -729,9 +800,10 @@ pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
extern VALUE rb_last_status; extern VALUE rb_last_status;
int int
do_spawn(mode, cmd) rb_w32_spawn(mode, cmd, prog)
int mode; int mode;
char *cmd; char *cmd;
char *prog;
{ {
struct ChildRecord *child; struct ChildRecord *child;
DWORD exitcode; DWORD exitcode;
@ -746,7 +818,7 @@ char *cmd;
return -1; return -1;
} }
child = CreateChild(cmd, NULL, NULL, NULL, NULL, NULL); child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL);
if (!child) { if (!child) {
return -1; return -1;
} }
@ -768,97 +840,15 @@ char *cmd;
} }
int int
do_aspawn(mode, prog, argv) rb_w32_aspawn(mode, prog, argv)
int mode; int mode;
char *prog; char *prog;
char **argv; char **argv;
{ {
char *cmd, *p, *q, *s, **t; int len = rb_w32_argv_size(argv);
int len, n, bs, quote; char *cmd = ALLOCA_N(char, len);
struct ChildRecord *child;
DWORD exitcode;
switch (mode) { return rb_w32_spawn(mode, rb_w32_join_argv(cmd, argv), prog);
case P_WAIT:
case P_NOWAIT:
case P_OVERLAY:
break;
default:
errno = EINVAL;
return -1;
}
for (t = argv, len = 0; *t; t++) {
for (p = *t, n = quote = bs = 0; *p; ++p) {
switch (*p) {
case '\\':
++bs;
break;
case '"':
n += bs + 1; bs = 0;
quote = 1;
break;
case ' ': case '\t':
quote = 1;
default:
bs = 0;
p = CharNext(p) - 1;
break;
}
}
len += p - *t + n + 1;
if (quote) len += 2;
}
cmd = ALLOCA_N(char, len);
for (t = argv, q = cmd; p = *t; t++) {
quote = 0;
s = p;
if (!*p || strpbrk(p, " \t\"")) {
quote = 1;
*q++ = '"';
}
for (bs = 0; *p; ++p) {
switch (*p) {
case '\\':
++bs;
break;
case '"':
memcpy(q, s, n = p - s); q += n; s = p;
memset(q, '\\', ++bs); q += bs; bs = 0;
break;
default:
bs = 0;
p = CharNext(p) - 1;
break;
}
}
memcpy(q, s, n = p - s);
q += n;
if (quote) *q++ = '"';
*q++ = ' ';
}
if (q > cmd) --q;
*q = '\0';
child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL);
if (!child) {
return -1;
}
switch (mode) {
case P_WAIT:
rb_syswait(child->pid);
return NUM2INT(rb_last_status);
case P_NOWAIT:
return child->pid;
case P_OVERLAY:
WaitForSingleObject(child->hProcess, INFINITE);
GetExitCodeProcess(child->hProcess, &exitcode);
CloseChildHandle(child);
_exit(exitcode);
default:
return -1; /* not reached */
}
} }
static struct ChildRecord * static struct ChildRecord *

Просмотреть файл

@ -120,7 +120,7 @@ extern "C++" {
#undef stat #undef stat
#define stat(path,st) rb_w32_stat(path,st) #define stat(path,st) rb_w32_stat(path,st)
#undef execv #undef execv
#define execv(path,argv) do_aspawn(P_OVERLAY,path,argv) #define execv(path,argv) rb_w32_aspawn(P_OVERLAY,path,argv)
#ifdef __MINGW32__ #ifdef __MINGW32__
struct timezone { struct timezone {
@ -175,8 +175,10 @@ extern int chown(const char *, int, int);
extern int link(const char *, const char *); extern int link(const char *, const char *);
extern int gettimeofday(struct timeval *, struct timezone *); extern int gettimeofday(struct timeval *, struct timezone *);
extern pid_t waitpid (pid_t, int *, int); extern pid_t waitpid (pid_t, int *, int);
extern int do_spawn(int, char *); extern int rb_w32_argv_size(char **);
extern int do_aspawn(int, char *, char **); extern char *rb_w32_join_argv(char *, char **);
extern int rb_w32_spawn(int, char *, char*);
extern int rb_w32_aspawn(int, char *, char **);
extern int kill(int, int); extern int kill(int, int);
extern pid_t rb_w32_getpid(void); extern pid_t rb_w32_getpid(void);