зеркало из https://github.com/github/ruby.git
* 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:
Родитель
3bc0f22fce
Коммит
03d8c88b87
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>
|
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\
|
||||||
|
|
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
|
* 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 */
|
||||||
|
|
292
io.c
292
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())) {
|
rb_sys_fail(pname);
|
||||||
case 0: /* child */
|
}
|
||||||
|
if ((modef & FMODE_WRITABLE) && pipe(arg.pw) == -1) {
|
||||||
if (modef & FMODE_READABLE) {
|
if (modef & FMODE_READABLE) {
|
||||||
close(pr[0]);
|
int e = errno;
|
||||||
if (pr[1] != 1) {
|
close(arg.pr[0]); close(arg.pr[1]);
|
||||||
dup2(pr[1], 1);
|
errno = e;
|
||||||
close(pr[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (modef & FMODE_WRITABLE) {
|
|
||||||
close(pw[1]);
|
|
||||||
if (pw[0] != 0) {
|
|
||||||
dup2(pw[0], 0);
|
|
||||||
close(pw[0]);
|
|
||||||
}
|
}
|
||||||
|
rb_sys_fail(pname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doexec) {
|
if (doexec) {
|
||||||
int fd;
|
arg.exec.argc = argc;
|
||||||
|
arg.exec.argv = argv;
|
||||||
for (fd = 3; fd < NOFILE; fd++)
|
arg.exec.prog = pname;
|
||||||
close(fd);
|
pid = rb_fork(&status, popen_exec, &arg);
|
||||||
rb_proc_exec(pname);
|
|
||||||
fprintf(stderr, "%s:%d: command not found: %s\n",
|
|
||||||
ruby_sourcefile, ruby_sourceline, pname);
|
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
|
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_stdout)->fptr);
|
||||||
rb_io_synchronized(RFILE(orig_stderr)->fptr);
|
rb_io_synchronized(RFILE(orig_stderr)->fptr);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
|
||||||
case -1: /* fork failed */
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
rb_thread_sleep(1);
|
|
||||||
goto retry;
|
|
||||||
}
|
}
|
||||||
close(pr[0]); close(pw[1]);
|
}
|
||||||
|
|
||||||
|
/* 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);
|
rb_sys_fail(pname);
|
||||||
break;
|
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);
|
||||||
|
|
||||||
default: /* parent */
|
if (!fpr) rb_sys_fail(pname);
|
||||||
if (pid < 0) rb_sys_fail(pname);
|
#define PIPE_FDOPEN(i) (fpr)
|
||||||
else {
|
#endif
|
||||||
VALUE port = io_alloc(rb_cIO);
|
|
||||||
|
|
||||||
|
port = io_alloc(rb_cIO);
|
||||||
MakeOpenFile(port, fptr);
|
MakeOpenFile(port, fptr);
|
||||||
fptr->mode = modef;
|
fptr->mode = modef | FMODE_SYNC;
|
||||||
fptr->mode |= FMODE_SYNC;
|
|
||||||
fptr->pid = pid;
|
fptr->pid = pid;
|
||||||
|
|
||||||
if (modef & FMODE_READABLE) {
|
if (modef & FMODE_READABLE) {
|
||||||
close(pr[1]);
|
fptr->f = PIPE_FDOPEN(0);
|
||||||
fptr->f = rb_fdopen(pr[0], "r");
|
|
||||||
}
|
}
|
||||||
if (modef & FMODE_WRITABLE) {
|
if (modef & FMODE_WRITABLE) {
|
||||||
FILE *f = rb_fdopen(pw[1], "w");
|
fpw = PIPE_FDOPEN(1);
|
||||||
|
if (fptr->f) fptr->f2 = fpw;
|
||||||
close(pw[0]);
|
else fptr->f = fpw;
|
||||||
if (fptr->f) fptr->f2 = f;
|
|
||||||
else fptr->f = f;
|
|
||||||
}
|
}
|
||||||
#if defined (__CYGWIN__)
|
#if defined (__CYGWIN__) || !defined(HAVE_FORK)
|
||||||
fptr->finalize = pipe_finalize;
|
fptr->finalize = pipe_finalize;
|
||||||
pipe_add_fptr(fptr);
|
pipe_add_fptr(fptr);
|
||||||
#endif
|
#endif
|
||||||
return port;
|
return port;
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
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 */
|
||||||
|
|
170
win32/win32.c
170
win32/win32.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);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче