--- ruby-1.9.3-p194/io.c 2012-04-14 14:36:06.000000000 -0500 +++ /Users/dlampa/carrier-build-root/local_build/carrier-ruby-1.9.3p194-2/src/ruby-build/ruby-source/io.c 2012-10-10 09:02:34.000000000 -0500 @@ -161,6 +161,62 @@ if (max_file_descriptor < fd) max_file_descriptor = fd; } +void +rb_maygvl_fd_fix_cloexec(int fd) +{ + /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */ +#ifdef F_GETFD + int flags, flags2, ret; + flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */ + if (flags == -1) { + rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno)); + } + if (fd <= 2) + flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */ + else + flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */ + if (flags != flags2) { + ret = fcntl(fd, F_SETFD, flags2); + if (ret == -1) { + rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno)); + } + } +#endif +} + +int +rb_cloexec_fcntl_dupfd(int fd, int minfd) +{ + int ret; + +#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) + static int try_dupfd_cloexec = 1; + if (try_dupfd_cloexec) { + ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd); + if (ret != -1) { + if (ret <= 2) + rb_maygvl_fd_fix_cloexec(ret); + return ret; + } + /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */ + if (errno == EINVAL) { + ret = fcntl(fd, F_DUPFD, minfd); + if (ret != -1) { + try_dupfd_cloexec = 0; + } + } + } + else { + ret = fcntl(fd, F_DUPFD, minfd); + } +#else + ret = fcntl(fd, F_DUPFD, minfd); +#endif + if (ret == -1) return -1; + rb_maygvl_fd_fix_cloexec(ret); + return ret; +} + #define argf_of(obj) (*(struct argf *)DATA_PTR(obj)) #define ARGF argf_of(argf) @@ -7918,60 +7974,203 @@ return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args); } -struct io_cntl_arg { +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + typedef unsigned long ioctl_req_t; + #define NUM2IOCTLREQ(num) NUM2ULONG(num) +#else + typedef int ioctl_req_t; + #define NUM2IOCTLREQ(num) NUM2INT(num) +#endif + +struct ioctl_arg { int fd; - int cmd; + ioctl_req_t cmd; long narg; - int io_p; }; -static VALUE nogvl_io_cntl(void *ptr) +static VALUE nogvl_ioctl(void *ptr) { - struct io_cntl_arg *arg = ptr; + struct ioctl_arg *arg = ptr; - if (arg->io_p) - return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg); - else - return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg); + return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg); } static int -io_cntl(int fd, int cmd, long narg, int io_p) +do_ioctl(int fd, ioctl_req_t cmd, long narg) { int retval; - struct io_cntl_arg arg; - -#ifndef HAVE_FCNTL - if (!io_p) { - rb_notimplement(); - } -#endif + struct ioctl_arg arg; arg.fd = fd; arg.cmd = cmd; arg.narg = narg; - arg.io_p = io_p; - retval = (int)rb_thread_io_blocking_region(nogvl_io_cntl, &arg, fd); -#if defined(F_DUPFD) - if (!io_p && retval != -1 && cmd == F_DUPFD) { - rb_update_max_fd(retval); - } -#endif + retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd); return retval; } -static VALUE -rb_io_ctl(VALUE io, VALUE req, VALUE arg, int io_p) +static long +ioctl_narg_len(ioctl_req_t cmd) { - int cmd = NUM2INT(req); - rb_io_t *fptr; - long len = 0; - long narg = 0; - int retval; + long len; - rb_secure(2); +#ifdef IOCPARM_MASK +#ifndef IOCPARM_LEN +#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) +#endif +#endif +#ifdef IOCPARM_LEN + len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */ +#elif defined(_IOC_SIZE) + len = _IOC_SIZE(cmd); +#else + len = 256; /* otherwise guess at what's safe */ +#endif + + return len; +} + +#ifdef HAVE_FCNTL +#ifdef __linux__ +typedef long fcntl_arg_t; +#else +/* posix */ +typedef int fcntl_arg_t; +#endif + +static long +fcntl_narg_len(int cmd) +{ + long len; + + switch (cmd) { +#ifdef F_DUPFD + case F_DUPFD: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_DUP2FD /* bsd specific */ + case F_DUP2FD: + len = sizeof(int); + break; +#endif +#ifdef F_DUPFD_CLOEXEC /* linux specific */ + case F_DUPFD_CLOEXEC: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_GETFD + case F_GETFD: + len = 1; + break; +#endif +#ifdef F_SETFD + case F_SETFD: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_GETFL + case F_GETFL: + len = 1; + break; +#endif +#ifdef F_SETFL + case F_SETFL: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_GETOWN + case F_GETOWN: + len = 1; + break; +#endif +#ifdef F_SETOWN + case F_SETOWN: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_GETOWN_EX /* linux specific */ + case F_GETOWN_EX: + len = sizeof(struct f_owner_ex); + break; +#endif +#ifdef F_SETOWN_EX /* linux specific */ + case F_SETOWN_EX: + len = sizeof(struct f_owner_ex); + break; +#endif +#ifdef F_GETLK + case F_GETLK: + len = sizeof(struct flock); + break; +#endif +#ifdef F_SETLK + case F_SETLK: + len = sizeof(struct flock); + break; +#endif +#ifdef F_SETLKW + case F_SETLKW: + len = sizeof(struct flock); + break; +#endif +#ifdef F_READAHEAD /* bsd specific */ + case F_READAHEAD: + len = sizeof(int); + break; +#endif +#ifdef F_RDAHEAD /* Darwin specific */ + case F_RDAHEAD: + len = sizeof(int); + break; +#endif +#ifdef F_GETSIG /* linux specific */ + case F_GETSIG: + len = 1; + break; +#endif +#ifdef F_SETSIG /* linux specific */ + case F_SETSIG: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_GETLEASE /* linux specific */ + case F_GETLEASE: + len = 1; + break; +#endif +#ifdef F_SETLEASE /* linux specific */ + case F_SETLEASE: + len = sizeof(fcntl_arg_t); + break; +#endif +#ifdef F_NOTIFY /* linux specific */ + case F_NOTIFY: + len = sizeof(fcntl_arg_t); + break; +#endif + + default: + len = 256; + break; + } + + return len; +} +#else /* HAVE_FCNTL */ +static long +fcntl_narg_len(int cmd) +{ + return 0; +} +#endif /* HAVE_FCNTL */ + +static long +setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p) +{ + long narg = 0; + VALUE arg = *argp; if (NIL_P(arg) || arg == Qfalse) { narg = 0; @@ -7989,50 +8188,50 @@ narg = NUM2LONG(arg); } else { - arg = tmp; -#ifdef IOCPARM_MASK -#ifndef IOCPARM_LEN -#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) -#endif -#endif -#ifdef IOCPARM_LEN - len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */ -#else - len = 256; /* otherwise guess at what's safe */ -#endif + long len; + + *argp = arg = tmp; + if (io_p) + len = ioctl_narg_len(cmd); + else + len = fcntl_narg_len((int)cmd); rb_str_modify(arg); - if (len <= RSTRING_LEN(arg)) { - len = RSTRING_LEN(arg); - } - if (RSTRING_LEN(arg) < len) { + /* expand for data + sentinel. */ + if (RSTRING_LEN(arg) < len+1) { rb_str_resize(arg, len+1); } - RSTRING_PTR(arg)[len] = 17; /* a little sanity check here */ + /* a little sanity check here */ + RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17; narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg); } } - GetOpenFile(io, fptr); - retval = io_cntl(fptr->fd, cmd, narg, io_p); - if (retval < 0) rb_sys_fail_path(fptr->pathv); - if (TYPE(arg) == T_STRING && RSTRING_PTR(arg)[len] != 17) { - rb_raise(rb_eArgError, "return value overflowed string"); + return narg; } - if (!io_p && cmd == F_SETFL) { - if (narg & O_NONBLOCK) { - fptr->mode |= FMODE_WSPLIT_INITIALIZED; - fptr->mode &= ~FMODE_WSPLIT; - } - else { - fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT); - } +static VALUE +rb_ioctl(VALUE io, VALUE req, VALUE arg) +{ + ioctl_req_t cmd = NUM2IOCTLREQ(req); + rb_io_t *fptr; + long narg; + int retval; + + rb_secure(2); + + narg = setup_narg(cmd, &arg, 1); + GetOpenFile(io, fptr); + retval = do_ioctl(fptr->fd, cmd, narg); + if (retval < 0) rb_sys_fail_path(fptr->pathv); + if (RB_TYPE_P(arg, T_STRING)) { + if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17) + rb_raise(rb_eArgError, "return value overflowed string"); + RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0'; } return INT2NUM(retval); } - /* * call-seq: * ios.ioctl(integer_cmd, arg) -> integer @@ -8051,10 +8250,80 @@ VALUE req, arg; rb_scan_args(argc, argv, "11", &req, &arg); - return rb_io_ctl(io, req, arg, 1); + return rb_ioctl(io, req, arg); } #ifdef HAVE_FCNTL +struct fcntl_arg { + int fd; + int cmd; + long narg; +}; + +static VALUE nogvl_fcntl(void *ptr) +{ + struct fcntl_arg *arg = ptr; + +#if defined(F_DUPFD) + if (arg->cmd == F_DUPFD) + return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg); +#endif + return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg); +} + +static int +do_fcntl(int fd, int cmd, long narg) +{ + int retval; + struct fcntl_arg arg; + + arg.fd = fd; + arg.cmd = cmd; + arg.narg = narg; + + retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd); +#if defined(F_DUPFD) + if (retval != -1 && cmd == F_DUPFD) { + rb_update_max_fd(retval); + } +#endif + + return retval; +} + +static VALUE +rb_fcntl(VALUE io, VALUE req, VALUE arg) +{ + int cmd = NUM2INT(req); + rb_io_t *fptr; + long narg; + int retval; + + rb_secure(2); + + narg = setup_narg(cmd, &arg, 0); + GetOpenFile(io, fptr); + retval = do_fcntl(fptr->fd, cmd, narg); + if (retval < 0) rb_sys_fail_path(fptr->pathv); + if (RB_TYPE_P(arg, T_STRING)) { + if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17) + rb_raise(rb_eArgError, "return value overflowed string"); + RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0'; + } + + if (cmd == F_SETFL) { + if (narg & O_NONBLOCK) { + fptr->mode |= FMODE_WSPLIT_INITIALIZED; + fptr->mode &= ~FMODE_WSPLIT; + } + else { + fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT); + } + } + + return INT2NUM(retval); +} + /* * call-seq: * ios.fcntl(integer_cmd, arg) -> integer @@ -8074,7 +8343,7 @@ VALUE req, arg; rb_scan_args(argc, argv, "11", &req, &arg); - return rb_io_ctl(io, req, arg, 0); + return rb_fcntl(io, req, arg); } #else #define rb_io_fcntl rb_f_notimplement