summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-10-11 06:47:36 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-10-11 06:47:36 +0000
commitcf7a5afaee39d39bd99a6c1618622962a95773b0 (patch)
tree169cfea203d70d735f12230ae7fbefb96ae7e94c
parent6249dac0aecb125b9acf069f502335cfcc29c2af (diff)
merge revision(s) 33711,33713,33714,33715,33716,33717,33718,33719,33720,33721,33724,33727,33728,33752,33753: [Backport #6127]
* io.c (ioctl_req_t): Type of req argument of ioctl() depend on platform. Moreover almost all linux ioctl can't be represented by 32bit integer (i.e. MSB is 1). We need wrap ioctl argument type. [Bug #5429] [ruby-dev:44589] * io.c (struct ioctl_arg): ditto. * io.c (rb_ioctl): ditto. * test/ruby/test_io.rb (test_ioctl_linux): add a testcase for ioctl * backporting patch is created by Donovan Lampa. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@37138 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--io.c397
1 files changed, 333 insertions, 64 deletions
diff --git a/io.c b/io.c
index bb75ece9e4..4526d4590a 100644
--- a/io.c
+++ b/io.c
@@ -161,6 +161,62 @@ rb_update_max_fd(int fd)
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)
@@ -7927,60 +7983,203 @@ rb_f_select(int argc, VALUE *argv, VALUE obj)
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;
@@ -7998,50 +8197,50 @@ rb_io_ctl(VALUE io, VALUE req, VALUE arg, int io_p)
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
@@ -8060,10 +8259,80 @@ rb_io_ioctl(int argc, VALUE *argv, VALUE io)
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
@@ -8083,7 +8352,7 @@ rb_io_fcntl(int argc, VALUE *argv, VALUE io)
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