1
0
Fork 0
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:
nobu 2004-02-16 06:45:32 +00:00
parent 3bc0f22fce
commit 03d8c88b87
7 changed files with 563 additions and 407 deletions

View file

@ -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.

View file

@ -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\

View file

@ -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
View file

@ -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
View file

@ -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 */

View file

@ -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 *

View file

@ -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);