mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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:
parent
3bc0f22fce
commit
03d8c88b87
7 changed files with 563 additions and 407 deletions
25
ChangeLog
25
ChangeLog
|
@ -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>
|
||||
|
||||
* 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\
|
||||
strchr strstr strtoul crypt flock vsnprintf\
|
||||
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\
|
||||
setitimer setruid seteuid setreuid setresuid setproctitle\
|
||||
setrgid setegid setregid setresgid issetugid pause lchown lchmod\
|
||||
|
|
15
intern.h
15
intern.h
|
@ -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
|
||||
* the kernel.
|
||||
|
@ -335,10 +338,20 @@ VALUE rb_lastline_get _((void));
|
|||
void rb_lastline_set _((VALUE));
|
||||
VALUE rb_sym_all_symbols _((void));
|
||||
/* 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*));
|
||||
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*));
|
||||
int rb_waitpid _((int,int*,int));
|
||||
void rb_syswait _((int));
|
||||
int rb_spawn _((int, VALUE*));
|
||||
VALUE rb_proc_times _((VALUE));
|
||||
VALUE rb_detach_process _((int));
|
||||
/* range.c */
|
||||
|
@ -486,3 +499,5 @@ VALUE rb_mod_remove_cvar _((VALUE, VALUE));
|
|||
/* version.c */
|
||||
void ruby_show_version _((void));
|
||||
void ruby_show_copyright _((void));
|
||||
|
||||
#endif /* RUBY_INTERN_H */
|
||||
|
|
330
io.c
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);
|
||||
}
|
||||
|
||||
#if defined (_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__VMS)
|
||||
#if defined(__CYGWIN__) || !defined(HAVE_FORK)
|
||||
static struct pipe_list {
|
||||
OpenFile *fptr;
|
||||
struct pipe_list *next;
|
||||
|
@ -2510,7 +2510,7 @@ pipe_finalize(fptr, noraise)
|
|||
OpenFile *fptr;
|
||||
int noraise;
|
||||
{
|
||||
#if !defined (__CYGWIN__) && !defined(_WIN32)
|
||||
#if !defined(HAVE_FORK) && !defined(_WIN32)
|
||||
extern VALUE rb_last_status;
|
||||
int status;
|
||||
if (fptr->f) {
|
||||
|
@ -2545,152 +2545,178 @@ rb_io_unbuffered(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
|
||||
pipe_open(pname, mode)
|
||||
pipe_open(argc, argv, pname, mode)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
char *pname, *mode;
|
||||
{
|
||||
int modef = rb_io_mode_flags(mode);
|
||||
int pid = 0;
|
||||
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;
|
||||
|
||||
retry:
|
||||
pid = pipe_exec(pname, rb_io_mode_modenum(mode), &fpr, &fpw);
|
||||
if (pid == -1) { /* exec failed */
|
||||
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];
|
||||
VALUE port, arg0;
|
||||
#if defined(HAVE_FORK)
|
||||
int status;
|
||||
struct popen_arg arg;
|
||||
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) ||
|
||||
((modef & FMODE_WRITABLE) && pipe(pw) == -1))
|
||||
rb_sys_fail(pname);
|
||||
if (!pname) {
|
||||
arg0 = rb_check_argv(argc, argv);
|
||||
if (arg0) pname = StringValuePtr(arg0);
|
||||
}
|
||||
|
||||
doexec = (strcmp("-", pname) != 0);
|
||||
#if defined(HAVE_FORK)
|
||||
doexec = (argc > 0) || (strcmp("-", pname) != 0);
|
||||
if (!doexec) {
|
||||
fflush(stdin); /* is it really needed? */
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
retry:
|
||||
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]);
|
||||
arg.pr[0] = arg.pr[1] = arg.pw[0] = arg.pw[1] = -1;
|
||||
if ((modef & FMODE_READABLE) && pipe(arg.pr) == -1) {
|
||||
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 (pid < 0) 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) {
|
||||
close(pr[1]);
|
||||
fptr->f = rb_fdopen(pr[0], "r");
|
||||
}
|
||||
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;
|
||||
if (doexec) {
|
||||
arg.exec.argc = argc;
|
||||
arg.exec.argv = argv;
|
||||
arg.exec.prog = pname;
|
||||
pid = rb_fork(&status, popen_exec, &arg);
|
||||
}
|
||||
else {
|
||||
pid = rb_fork(&status, 0, 0);
|
||||
if (pid == 0) { /* child */
|
||||
popen_redirect(&arg);
|
||||
rb_io_synchronized(RFILE(orig_stdout)->fptr);
|
||||
rb_io_synchronized(RFILE(orig_stderr)->fptr);
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
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
|
||||
|
||||
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
|
||||
|
@ -2714,7 +2740,7 @@ rb_io_popen(str, argc, argv, klass)
|
|||
mode = StringValuePtr(pmode);
|
||||
}
|
||||
SafeStringValue(pname);
|
||||
port = pipe_open(str, mode);
|
||||
port = pipe_open(0, 0, str, mode);
|
||||
if (NIL_P(port)) {
|
||||
/* child */
|
||||
if (rb_block_given_p()) {
|
||||
|
@ -2779,12 +2805,46 @@ rb_io_s_popen(argc, argv, klass)
|
|||
VALUE *argv;
|
||||
VALUE klass;
|
||||
{
|
||||
char *str = 0;
|
||||
char *mode;
|
||||
VALUE pname, pmode, port, tmp;
|
||||
char mbuf[4];
|
||||
|
||||
if (argc >= 1) {
|
||||
str = StringValuePtr(argv[0]);
|
||||
if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
|
||||
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
|
||||
|
@ -2985,7 +3045,7 @@ rb_io_open(fname, mode)
|
|||
char *fname, *mode;
|
||||
{
|
||||
if (fname[0] == '|') {
|
||||
return pipe_open(fname+1, mode);
|
||||
return pipe_open(0, 0, fname+1, mode);
|
||||
}
|
||||
else {
|
||||
return rb_file_open(fname, mode);
|
||||
|
@ -4179,7 +4239,7 @@ rb_f_backquote(obj, str)
|
|||
OpenFile *fptr;
|
||||
|
||||
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);
|
||||
|
||||
GetOpenFile(port, fptr);
|
||||
|
|
420
process.c
420
process.c
|
@ -23,6 +23,9 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef __DJGPP__
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
@ -912,12 +915,16 @@ proc_exec_v(argv, prog)
|
|||
char **argv;
|
||||
char *prog;
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!prog)
|
||||
prog = argv[0];
|
||||
security(prog);
|
||||
prog = dln_find_exe(prog, 0);
|
||||
if (!prog)
|
||||
if (!prog) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#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__ */
|
||||
before_exec();
|
||||
execv(prog, argv);
|
||||
err = errno;
|
||||
after_exec();
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
proc_exec_n(argc, argv, progv)
|
||||
int
|
||||
rb_proc_exec_n(argc, argv, prog)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
VALUE progv;
|
||||
const char *prog;
|
||||
{
|
||||
char *prog = 0;
|
||||
char **args;
|
||||
int i;
|
||||
|
||||
if (progv) {
|
||||
prog = RSTRING(progv)->ptr;
|
||||
}
|
||||
args = ALLOCA_N(char*, argc+1);
|
||||
for (i=0; i<argc; i++) {
|
||||
SafeStringValue(argv[i]);
|
||||
args[i] = RSTRING(argv[i])->ptr;
|
||||
}
|
||||
args[i] = 0;
|
||||
|
@ -1000,22 +1004,21 @@ rb_proc_exec(str)
|
|||
|
||||
#ifdef _WIN32
|
||||
before_exec();
|
||||
do_spawn(P_OVERLAY, (char *)str);
|
||||
rb_w32_spawn(P_OVERLAY, (char *)str, 0);
|
||||
after_exec();
|
||||
#else
|
||||
for (s=str; *s; s++) {
|
||||
if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
|
||||
#if defined(MSDOS)
|
||||
int status;
|
||||
#if defined(MSDOS)
|
||||
before_exec();
|
||||
status = system(str);
|
||||
after_exec();
|
||||
if (status != -1)
|
||||
exit(status);
|
||||
#else
|
||||
#if defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
|
||||
#elif defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
|
||||
char *shell = dln_find_exe("sh", 0);
|
||||
int status = -1;
|
||||
status = -1;
|
||||
before_exec();
|
||||
if (shell)
|
||||
execl(shell, "sh", "-c", str, (char *) NULL);
|
||||
|
@ -1027,8 +1030,9 @@ rb_proc_exec(str)
|
|||
#else
|
||||
before_exec();
|
||||
execl("/bin/sh", "sh", "-c", str, (char *)NULL);
|
||||
status = errno;
|
||||
after_exec();
|
||||
#endif
|
||||
errno = status;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
@ -1050,12 +1054,20 @@ rb_proc_exec(str)
|
|||
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
|
||||
proc_spawn_v(argv, prog)
|
||||
char **argv;
|
||||
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;
|
||||
int status;
|
||||
|
||||
|
@ -1091,13 +1103,10 @@ proc_spawn_v(argv, prog)
|
|||
}
|
||||
#endif
|
||||
before_exec();
|
||||
#if defined(_WIN32)
|
||||
status = do_aspawn(P_WAIT, prog, argv);
|
||||
#else
|
||||
status = spawnv(P_WAIT, prog, argv);
|
||||
#endif
|
||||
after_exec();
|
||||
return status;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1111,29 +1120,25 @@ proc_spawn_n(argc, argv, prog)
|
|||
|
||||
args = ALLOCA_N(char*, argc + 1);
|
||||
for (i = 0; i < argc; i++) {
|
||||
SafeStringValue(argv[i]);
|
||||
args[i] = RSTRING(argv[i])->ptr;
|
||||
}
|
||||
if (prog)
|
||||
SafeStringValue(prog);
|
||||
args[i] = (char*) 0;
|
||||
if (args[0])
|
||||
return proc_spawn_v(args, prog ? RSTRING(prog)->ptr : 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
#define proc_spawn(str) rb_w32_spawn(P_NOWAIT, str, 0)
|
||||
#else
|
||||
static int
|
||||
proc_spawn(sv)
|
||||
VALUE sv;
|
||||
{
|
||||
proc_spawn(str)
|
||||
char *str;
|
||||
{
|
||||
char *s, *t;
|
||||
char **argv, **a;
|
||||
int status;
|
||||
|
||||
SafeStringValue(sv);
|
||||
str = s = RSTRING(sv)->ptr;
|
||||
for (s = str; *s; s++) {
|
||||
if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
|
||||
char *shell = dln_find_exe("sh", 0);
|
||||
|
@ -1156,6 +1161,35 @@ proc_spawn(sv)
|
|||
#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:
|
||||
* exec(command [, arg, ...])
|
||||
|
@ -1186,35 +1220,116 @@ rb_f_exec(argc, argv)
|
|||
int argc;
|
||||
VALUE *argv;
|
||||
{
|
||||
VALUE prog = 0;
|
||||
VALUE tmp;
|
||||
struct rb_exec_arg e;
|
||||
VALUE prog;
|
||||
|
||||
if (argc == 0) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments");
|
||||
}
|
||||
|
||||
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);
|
||||
prog = rb_check_argv(argc, argv);
|
||||
if (!prog && argc == 1) {
|
||||
--argc;
|
||||
prog = *argv++;
|
||||
}
|
||||
e.argc = argc;
|
||||
e.argv = argv;
|
||||
e.prog = prog ? RSTRING(prog)->ptr : 0;
|
||||
rb_exec(&e);
|
||||
rb_sys_fail(RSTRING(argv[0])->ptr);
|
||||
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:
|
||||
|
@ -1227,11 +1342,12 @@ static VALUE
|
|||
rb_f_fork(obj)
|
||||
VALUE obj;
|
||||
{
|
||||
#if !defined(__human68k__) && !defined(_WIN32) && !defined(__MACOS__) && !defined(__EMX__) && !defined(__VMS)
|
||||
#ifdef HAVE_FORK
|
||||
int pid;
|
||||
|
||||
rb_secure(2);
|
||||
switch (pid = fork()) {
|
||||
|
||||
switch (pid = rb_fork(0, 0, 0)) {
|
||||
case 0:
|
||||
#ifdef linux
|
||||
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:
|
||||
* system(cmd [, arg, ...]) => true or false
|
||||
|
@ -1362,137 +1520,41 @@ rb_f_system(argc, argv)
|
|||
VALUE *argv;
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
|
||||
if (status == EXIT_SUCCESS) return Qtrue;
|
||||
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:
|
||||
* sleep(duration=0) => fixnum
|
||||
|
@ -3314,6 +3376,7 @@ Init_process()
|
|||
rb_define_global_function("fork", rb_f_fork, 0);
|
||||
rb_define_global_function("exit!", rb_f_exit_bang, -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_mProcess = rb_define_module("Process");
|
||||
|
@ -3332,6 +3395,7 @@ Init_process()
|
|||
#endif
|
||||
|
||||
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, -1); /* in eval.c */
|
||||
rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1); /* in eval.c */
|
||||
|
|
170
win32/win32.c
170
win32/win32.c
|
@ -589,8 +589,79 @@ rb_w32_get_osfhandle(int 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
|
||||
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;
|
||||
HANDLE hReadIn, hReadOut;
|
||||
|
@ -667,7 +738,7 @@ pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
|
|||
CloseHandle(hCurProc);
|
||||
|
||||
/* create child process */
|
||||
child = CreateChild(cmd, NULL, &sa, hWriteIn, hReadOut, NULL);
|
||||
child = CreateChild(cmd, prog, &sa, hWriteIn, hReadOut, NULL);
|
||||
if (!child) {
|
||||
if (reading) {
|
||||
CloseHandle(hReadOut);
|
||||
|
@ -729,9 +800,10 @@ pipe_exec(char *cmd, int mode, FILE **fpr, FILE **fpw)
|
|||
extern VALUE rb_last_status;
|
||||
|
||||
int
|
||||
do_spawn(mode, cmd)
|
||||
rb_w32_spawn(mode, cmd, prog)
|
||||
int mode;
|
||||
char *cmd;
|
||||
char *prog;
|
||||
{
|
||||
struct ChildRecord *child;
|
||||
DWORD exitcode;
|
||||
|
@ -746,7 +818,7 @@ char *cmd;
|
|||
return -1;
|
||||
}
|
||||
|
||||
child = CreateChild(cmd, NULL, NULL, NULL, NULL, NULL);
|
||||
child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL);
|
||||
if (!child) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -768,97 +840,15 @@ char *cmd;
|
|||
}
|
||||
|
||||
int
|
||||
do_aspawn(mode, prog, argv)
|
||||
rb_w32_aspawn(mode, prog, argv)
|
||||
int mode;
|
||||
char *prog;
|
||||
char **argv;
|
||||
{
|
||||
char *cmd, *p, *q, *s, **t;
|
||||
int len, n, bs, quote;
|
||||
struct ChildRecord *child;
|
||||
DWORD exitcode;
|
||||
int len = rb_w32_argv_size(argv);
|
||||
char *cmd = ALLOCA_N(char, len);
|
||||
|
||||
switch (mode) {
|
||||
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 */
|
||||
}
|
||||
return rb_w32_spawn(mode, rb_w32_join_argv(cmd, argv), prog);
|
||||
}
|
||||
|
||||
static struct ChildRecord *
|
||||
|
|
|
@ -120,7 +120,7 @@ extern "C++" {
|
|||
#undef stat
|
||||
#define stat(path,st) rb_w32_stat(path,st)
|
||||
#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__
|
||||
struct timezone {
|
||||
|
@ -175,8 +175,10 @@ extern int chown(const char *, int, int);
|
|||
extern int link(const char *, const char *);
|
||||
extern int gettimeofday(struct timeval *, struct timezone *);
|
||||
extern pid_t waitpid (pid_t, int *, int);
|
||||
extern int do_spawn(int, char *);
|
||||
extern int do_aspawn(int, char *, char **);
|
||||
extern int rb_w32_argv_size(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 pid_t rb_w32_getpid(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue