From aa5c05b8ba0c1ab9255730f8cd7acab68c0af600 Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 2 Sep 2010 21:40:55 +0000 Subject: * ext/pty/pty.c (chfunc): pass through exceptions. * io.c (rb_io_bufwrite, rb_io_bufread): added. * process.c (rb_fork_err): protect from exceptions. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29171 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 8 ++++++ ext/pty/pty.c | 26 +----------------- io.c | 88 +++++++++++++++++++++++++++++++++++++++++------------------ process.c | 60 +++++++++++++++++++++++++++++++++++----- 4 files changed, 124 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index ba3c2ca367..0078399940 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Fri Sep 3 06:40:44 2010 Nobuyoshi Nakada + + * ext/pty/pty.c (chfunc): pass through exceptions. + + * io.c (rb_io_bufwrite, rb_io_bufread): added. + + * process.c (rb_fork_err): protect from exceptions. + Fri Sep 3 06:16:07 2010 Tanaka Akira * ext/pathname/pathname.c (path_pipe_p): Pathname#pipe? diff --git a/ext/pty/pty.c b/ext/pty/pty.c index 156e4563c3..b2b5caa2af 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -135,18 +135,6 @@ struct pty_info { static void getDevice(int*, int*, char [DEVICELEN], int); -struct exec_info { - int argc; - VALUE *argv; -}; - -static VALUE -pty_exec(VALUE v) -{ - struct exec_info *arg = (struct exec_info *)v; - return rb_f_exec(arg->argc, arg->argv); -} - struct child_info { int master, slave; char *slavename; @@ -162,10 +150,7 @@ chfunc(void *data, char *errbuf, size_t errbuf_len) int slave = carg->slave; int argc = carg->argc; VALUE *argv = carg->argv; - VALUE exc; - struct exec_info arg; - int status; #define ERROR_EXIT(str) do { \ strlcpy(errbuf, str, errbuf_len); \ return -1; \ @@ -218,16 +203,7 @@ chfunc(void *data, char *errbuf, size_t errbuf_len) seteuid(getuid()); #endif - arg.argc = argc; - arg.argv = argv; - rb_protect(pty_exec, (VALUE)&arg, &status); - sleep(1); - errno = ENOENT; /* last resort */ - exc = rb_errinfo(); - if (!NIL_P(exc)) { - errno = NUM2INT(rb_attr_get(exc, rb_intern("errno"))); - } - ERROR_EXIT(StringValueCStr(argv[0])); + return rb_f_exec(argc, argv); #undef ERROR_EXIT } diff --git a/io.c b/io.c index 459528255e..169158b454 100644 --- a/io.c +++ b/io.c @@ -556,30 +556,36 @@ wsplit_p(rb_io_t *fptr) return fptr->mode & FMODE_WSPLIT; } -struct io_internal_struct { +struct io_internal_read_struct { int fd; void *buf; size_t capa; }; +struct io_internal_write_struct { + int fd; + const void *buf; + size_t capa; +}; + static VALUE internal_read_func(void *ptr) { - struct io_internal_struct *iis = (struct io_internal_struct*)ptr; + struct io_internal_read_struct *iis = ptr; return read(iis->fd, iis->buf, iis->capa); } static VALUE internal_write_func(void *ptr) { - struct io_internal_struct *iis = (struct io_internal_struct*)ptr; + struct io_internal_write_struct *iis = ptr; return write(iis->fd, iis->buf, iis->capa); } static ssize_t rb_read_internal(int fd, void *buf, size_t count) { - struct io_internal_struct iis; + struct io_internal_read_struct iis; iis.fd = fd; iis.buf = buf; iis.capa = count; @@ -588,9 +594,9 @@ rb_read_internal(int fd, void *buf, size_t count) } static ssize_t -rb_write_internal(int fd, void *buf, size_t count) +rb_write_internal(int fd, const void *buf, size_t count) { - struct io_internal_struct iis; + struct io_internal_write_struct iis; iis.fd = fd; iis.buf = buf; iis.capa = count; @@ -816,7 +822,7 @@ make_writeconv(rb_io_t *fptr) struct binwrite_arg { rb_io_t *fptr; VALUE str; - long offset; + const char *ptr; long length; }; @@ -825,15 +831,14 @@ io_binwrite_string(VALUE arg) { struct binwrite_arg *p = (struct binwrite_arg *)arg; long l = io_writable_length(p->fptr, p->length); - return rb_write_internal(p->fptr->fd, RSTRING_PTR(p->str)+p->offset, l); + return rb_write_internal(p->fptr->fd, p->ptr, l); } static long -io_binwrite(VALUE str, rb_io_t *fptr, int nosync) +io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) { - long len, n, r, offset = 0; + long n, r, offset = 0; - len = RSTRING_LEN(str); if ((n = len) <= 0) return n; if (fptr->wbuf == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) { fptr->wbuf_off = 0; @@ -852,7 +857,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync) MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len); fptr->wbuf_off = 0; } - MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len); + MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, ptr+offset, char, len); fptr->wbuf_len += (int)len; n = 0; } @@ -868,14 +873,14 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync) arg.fptr = fptr; arg.str = str; retry: - arg.offset = offset; + arg.ptr = ptr + offset; arg.length = n; if (fptr->write_lock) { r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg); } else { long l = io_writable_length(fptr, n); - r = rb_write_internal(fptr->fd, RSTRING_PTR(str)+offset, l); + r = rb_write_internal(fptr->fd, ptr+offset, l); } /* xxx: other threads may modify given string. */ if (r == n) return len; @@ -886,7 +891,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync) } if (rb_io_wait_writable(fptr->fd)) { rb_io_check_closed(fptr); - if (offset < RSTRING_LEN(str)) + if (offset < len) goto retry; } return -1L; @@ -897,7 +902,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync) MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len); fptr->wbuf_off = 0; } - MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len); + MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, ptr+offset, char, len); fptr->wbuf_len += (int)len; return len; } @@ -941,7 +946,18 @@ static long io_fwrite(VALUE str, rb_io_t *fptr, int nosync) { str = do_writeconv(str, fptr); - return io_binwrite(str, fptr, nosync); + return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), + fptr, nosync); +} + +ssize_t +rb_io_bufwrite(VALUE io, const void *buf, size_t size) +{ + rb_io_t *fptr; + + GetOpenFile(io, fptr); + rb_io_check_writable(fptr); + return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0); } static VALUE @@ -1520,33 +1536,31 @@ read_buffered_data(char *ptr, long len, rb_io_t *fptr) } static long -io_fread(VALUE str, long offset, rb_io_t *fptr) +io_bufread(char *ptr, long len, rb_io_t *fptr) { - long len = RSTRING_LEN(str) - offset; + long offset = 0; long n = len; long c; - rb_str_locktmp(str); if (READ_DATA_PENDING(fptr) == 0) { while (n > 0) { again: - c = rb_read_internal(fptr->fd, RSTRING_PTR(str)+offset, n); + c = rb_read_internal(fptr->fd, ptr+offset, n); if (c == 0) break; if (c < 0) { if (rb_io_wait_readable(fptr->fd)) goto again; - rb_sys_fail_path(fptr->pathv); + return -1; } offset += c; if ((n -= c) <= 0) break; rb_thread_wait_fd(fptr->fd); } - rb_str_unlocktmp(str); return len - n; } while (n > 0) { - c = read_buffered_data(RSTRING_PTR(str)+offset, n, fptr); + c = read_buffered_data(ptr+offset, n, fptr); if (c > 0) { offset += c; if ((n -= c) <= 0) break; @@ -1557,10 +1571,32 @@ io_fread(VALUE str, long offset, rb_io_t *fptr) break; } } - rb_str_unlocktmp(str); return len - n; } +static long +io_fread(VALUE str, long offset, rb_io_t *fptr) +{ + long len; + + rb_str_locktmp(str); + len = io_bufread(RSTRING_PTR(str) + offset, RSTRING_LEN(str) - offset, + fptr); + rb_str_unlocktmp(str); + if (len < 0) rb_sys_fail_path(fptr->pathv); + return len; +} + +ssize_t +rb_io_bufread(VALUE io, void *buf, size_t size) +{ + rb_io_t *fptr; + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + return (ssize_t)io_bufread(buf, (long)size, fptr); +} + #define SMALLBUF 100 static long @@ -8475,7 +8511,7 @@ copy_stream_body(VALUE arg) rb_str_resize(str,len); read_buffered_data(RSTRING_PTR(str), len, src_fptr); if (dst_fptr) { /* IO or filename */ - if (io_binwrite(str, dst_fptr, 0) < 0) + if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0) rb_sys_fail(0); } else /* others such as StringIO */ diff --git a/process.c b/process.c index b230add18b..e17fa582f7 100644 --- a/process.c +++ b/process.c @@ -137,6 +137,9 @@ static VALUE rb_cProcessTms; do {int saved_errno = errno; stmts; errno = saved_errno;} while (0) +ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size); +ssize_t rb_io_bufread(VALUE io, void *buf, size_t size); + /* * call-seq: * Process.pid -> fixnum @@ -2430,6 +2433,25 @@ pipe_nocrash(int filedes[2], VALUE fds) return ret; } +struct chfunc_protect_t { + int (*chfunc)(void*, char *, size_t); + void *arg; + char *errmsg; + size_t buflen; +}; + +static VALUE +chfunc_protect(VALUE arg) +{ + struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg; + + return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen); +} + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + /* * Forks child process, and returns the process ID in the parent * process. @@ -2461,6 +2483,7 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU int err, state = 0; #ifdef FD_CLOEXEC int ep[2]; + VALUE io = Qnil; #endif #define prefork() ( \ @@ -2507,19 +2530,30 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU if (!pid) { forked_child = 1; if (chfunc) { + struct chfunc_protect_t arg; + arg.chfunc = chfunc; + arg.arg = charg; + arg.errmsg = errmsg; + arg.buflen = errmsg_buflen; #ifdef FD_CLOEXEC close(ep[0]); #endif - if (!(*chfunc)(charg, errmsg, errmsg_buflen)) _exit(EXIT_SUCCESS); + if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS); #ifdef FD_CLOEXEC + if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) { + io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL); + rb_marshal_dump(rb_errinfo(), io); + rb_io_flush(io); + } err = errno; if (write(ep[1], &err, sizeof(err)) < 0) err = errno; if (errmsg && 0 < errmsg_buflen) { errmsg[errmsg_buflen-1] = '\0'; errmsg_buflen = strlen(errmsg); if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0) - err = errno; + err = errno; } + if (!NIL_P(io)) rb_io_close(io); #endif #if EXIT_SUCCESS == 127 _exit(EXIT_FAILURE); @@ -2532,25 +2566,37 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU #ifdef FD_CLOEXEC if (pid && chfunc) { ssize_t size; + VALUE exc = Qnil; close(ep[1]); - if ((size = read(ep[0], &err, sizeof(err))) < 0) { + if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) { + io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL); + exc = rb_marshal_load(io); + rb_set_errinfo(exc); + } +#define READ_FROM_CHILD(ptr, len) \ + (NIL_P(io) ? read(ep[0], ptr, len) : rb_io_bufread(io, ptr, len)) + if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) { err = errno; } if (size == sizeof(err) && errmsg && 0 < errmsg_buflen) { - ssize_t ret; - ret = read(ep[0], errmsg, errmsg_buflen-1); + ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1); if (0 <= ret) { errmsg[ret] = '\0'; } } - close(ep[0]); - if (size) { + if (NIL_P(io)) + close(ep[0]); + else + rb_io_close(io); + if (state || size) { if (status) { + *status = state; rb_protect(proc_syswait, (VALUE)pid, status); } else { rb_syswait(pid); + if (state) rb_exc_raise(exc); } errno = err; return -1; -- cgit v1.2.3