summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-02-16 06:45:32 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-02-16 06:45:32 +0000
commit03d8c88b8774d40f3ff2596d7658f84938923caa (patch)
treec284a1b3d52c3b37a17591fd6327f2011438653a /io.c
parent3bc0f22fcea84f09ba347a0575779f935e044c12 (diff)
* 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
Diffstat (limited to 'io.c')
-rw-r--r--io.c312
1 files changed, 186 insertions, 126 deletions
diff --git a/io.c b/io.c
index aeba25ad46..8e1a58bef6 100644
--- a/io.c
+++ b/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);
}
-static VALUE
-pipe_open(pname, mode)
- char *pname, *mode;
-{
- int modef = rb_io_mode_flags(mode);
- OpenFile *fptr;
-
-#if defined(DJGPP) || defined(__human68k__) || defined(__VMS)
- FILE *f = popen(pname, mode);
+struct popen_arg {
+ struct rb_exec_arg exec;
+ int pr[2], pw[2];
+};
- 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);
+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]);
}
- 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;
+ if (p->pw[0] != -1) {
+ close(p->pw[1]);
+ if (p->pw[0] != 0) {
+ dup2(p->pw[0], 0);
+ close(p->pw[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;
+#ifdef HAVE_FORK
+static int
+popen_exec(p)
+ struct popen_arg *p;
+{
+ int fd;
- 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;
- }
+ popen_redirect(p);
+ for (fd = 3; fd < NOFILE; fd++) {
+#ifdef FD_CLOEXEC
+ fcntl(fd, F_SETFL, FD_CLOEXEC);
#else
- int pid, pr[2], pw[2];
+ close(fd);
+#endif
+ }
+ return rb_exec(&p->exec);
+}
+#endif
+
+static VALUE
+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;
+ FILE *fpr, *fpw;
+ 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 */
+ 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);
+ }
+ if ((modef & FMODE_WRITABLE) && pipe(arg.pw) == -1) {
if (modef & FMODE_READABLE) {
- close(pr[0]);
- if (pr[1] != 1) {
- dup2(pr[1], 1);
- close(pr[1]);
- }
+ int e = errno;
+ close(arg.pr[0]); close(arg.pr[1]);
+ errno = e;
}
- if (modef & FMODE_WRITABLE) {
- close(pw[1]);
- if (pw[0] != 0) {
- dup2(pw[0], 0);
- close(pw[0]);
- }
+ rb_sys_fail(pname);
+ }
+
+ 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;
}
+ }
- if (doexec) {
- int fd;
+ /* 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 (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);
+ for (i = 0; i < argc; ++i) {
+ args[i] = RSTRING(argv[i])->ptr;
}
- rb_io_synchronized(RFILE(orig_stdout)->fptr);
- rb_io_synchronized(RFILE(orig_stderr)->fptr);
- return Qnil;
-
- case -1: /* fork failed */
- if (errno == EAGAIN) {
+ 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);
- goto retry;
+ break;
+ defined:
+ rb_sys_fail(pname);
+ break;
}
- close(pr[0]); close(pw[1]);
- rb_sys_fail(pname);
- break;
-
- default: /* parent */
- if (pid < 0) rb_sys_fail(pname);
- else {
- VALUE port = io_alloc(rb_cIO);
+ }
+#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);
- MakeOpenFile(port, fptr);
- fptr->mode = modef;
- fptr->mode |= FMODE_SYNC;
- fptr->pid = pid;
+ if (!fpr) rb_sys_fail(pname);
+#define PIPE_FDOPEN(i) (fpr)
+#endif
- 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");
+ port = io_alloc(rb_cIO);
+ MakeOpenFile(port, fptr);
+ fptr->mode = modef | FMODE_SYNC;
+ fptr->pid = pid;
- 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 (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
-#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";
+ }
+ else if (FIXNUM_P(pmode)) {
+ mode = rb_io_modenum_mode(FIX2INT(pmode), mbuf);
}
- return rb_io_popen(str, argc, argv, klass);
+ 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);