Project

General

Profile

Feature #5041 ยป close-on-exec-by-default.patch

akr (Akira Tanaka), 08/11/2011 02:43 PM

View differences:

NEWS (working copy)
30 30
  * Signal.trap
31 31

  
32 32
    See above.
33

  
34
  * incompatible changes:
35
    The :close_others option is true by default for system() and exec().
36
    The close on exec flag is set by default for all new file descriptors.
37
    This means file descriptors doesn't inherit to spawned process unless
38
    explicitly requested as system(..., fd=>fd).
include/ruby/intern.h (working copy)
501 501
int rb_reserved_fd_p(int fd);
502 502
#define RB_RESERVED_FD_P(fd) rb_reserved_fd_p(fd)
503 503
void rb_update_max_fd(int fd);
504
void rb_fd_set_cloexec(int fd);
504 505
/* marshal.c */
505 506
VALUE rb_marshal_dump(VALUE, VALUE);
506 507
VALUE rb_marshal_load(VALUE);
thread_pthread.c (working copy)
1207 1207
	    if (err != 0) {
1208 1208
		rb_bug_errno("thread_timer: Failed to create communication pipe for timer thread", errno);
1209 1209
	    }
1210
            rb_update_max_fd(timer_thread_pipe[0]);
1211
            rb_update_max_fd(timer_thread_pipe[1]);
1210
            rb_fd_set_cloexec(timer_thread_pipe[0]);
1211
            rb_fd_set_cloexec(timer_thread_pipe[1]);
1212 1212
#if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(F_SETFL)
1213 1213
	    {
1214 1214
		int oflags;
io.c (working copy)
157 157
    if (max_file_descriptor < fd) max_file_descriptor = fd;
158 158
}
159 159

  
160
void rb_fd_set_cloexec(int fd)
161
{
162
    int flags, ret;
163
    flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
164
    if (flags == -1) {
165
        rb_bug("rb_fd_set_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
166
    }
167
    if (2 < fd) {
168
        if (!(flags & FD_CLOEXEC)) {
169
            flags |= FD_CLOEXEC;
170
            ret = fcntl(fd, F_SETFD, flags);
171
            if (ret == -1) {
172
                rb_bug("rb_fd_set_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags, strerror(errno));
173
            }
174
        }
175
    }
176
    if (max_file_descriptor < fd) max_file_descriptor = fd;
177
}
178

  
160 179
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
161 180
#define ARGF argf_of(argf)
162 181

  
......
527 546
	    rb_sys_fail(0);
528 547
	}
529 548
    }
530
    rb_update_max_fd(fd);
549
    rb_fd_set_cloexec(fd);
531 550
    return fd;
532 551
}
533 552

  
......
4591 4610
    int fd;
4592 4611
    fd = (int)rb_thread_blocking_region(sysopen_func, data, RUBY_UBF_IO, 0);
4593 4612
    if (0 <= fd)
4594
        rb_update_max_fd(fd);
4613
        rb_fd_set_cloexec(fd);
4595 4614
    return fd;
4596 4615
}
4597 4616

  
......
4919 4938
    }
4920 4939
#endif
4921 4940
    if (ret == 0) {
4922
        rb_update_max_fd(pipes[0]);
4923
        rb_update_max_fd(pipes[1]);
4941
        rb_fd_set_cloexec(pipes[0]);
4942
        rb_fd_set_cloexec(pipes[1]);
4924 4943
    }
4925 4944
    return ret;
4926 4945
}
......
5802 5821
	    /* need to keep FILE objects of stdin, stdout and stderr */
5803 5822
	    if (dup2(fd2, fd) < 0)
5804 5823
		rb_sys_fail_path(orig->pathv);
5805
            rb_update_max_fd(fd);
5824
            rb_fd_set_cloexec(fd);
5806 5825
	}
5807 5826
	else {
5808 5827
            fclose(fptr->stdio_file);
......
5810 5829
            fptr->fd = -1;
5811 5830
            if (dup2(fd2, fd) < 0)
5812 5831
                rb_sys_fail_path(orig->pathv);
5813
            rb_update_max_fd(fd);
5832
            rb_fd_set_cloexec(fd);
5814 5833
            fptr->fd = fd;
5815 5834
	}
5816 5835
	rb_thread_fd_close(fd);
......
7702 7721
    retval = (int)rb_thread_io_blocking_region(nogvl_io_cntl, &arg, fd);
7703 7722
#if defined(F_DUPFD)
7704 7723
    if (!io_p && retval != -1 && cmd == F_DUPFD) {
7705
	rb_update_max_fd(retval);
7724
	rb_fd_set_cloexec(retval);
7706 7725
    }
7707 7726
#endif
7708 7727

  
process.c (working copy)
1857 1857

  
1858 1858
    rb_exec_arg_init(argc, argv, TRUE, &earg);
1859 1859
    if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS)))
1860
        rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), Qfalse);
1860
        rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), Qtrue);
1861 1861
    rb_exec_arg_fixup(&earg);
1862 1862

  
1863 1863
    rb_exec_err(&earg, errmsg, sizeof(errmsg));
......
2498 2498
            ret = fcntl(fdp[i], F_DUPFD, min);
2499 2499
            if (ret == -1)
2500 2500
                return -1;
2501
            rb_update_max_fd(ret);
2501
            rb_fd_set_cloexec(ret);
2502 2502
            close(fdp[i]);
2503 2503
            fdp[i] = ret;
2504 2504
        }
......
3076 3076

  
3077 3077
    chfunc = signal(SIGCHLD, SIG_DFL);
3078 3078
#endif
3079
    pid = rb_spawn_internal(argc, argv, FALSE, NULL, 0);
3079
    pid = rb_spawn_internal(argc, argv, TRUE, NULL, 0);
3080 3080
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
3081 3081
    if (pid > 0) {
3082 3082
	rb_syswait(pid);
......
3151 3151
 *          integer : the file descriptor of specified the integer
3152 3152
 *          io      : the file descriptor specified as io.fileno
3153 3153
 *      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
3154
 *        :close_others => false : inherit fds (default for system and exec)
3155
 *        :close_others => true  : don't inherit (default for spawn and IO.popen)
3154
 *        :close_others => true  : don't inherit
3156 3155
 *
3157 3156
 *  If a hash is given as +env+, the environment is
3158 3157
 *  updated by +env+ before <code>exec(2)</code> in the child process.
......
3547 3546
    if (ret == -1) return -1;
3548 3547

  
3549 3548
    if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
3550
        rb_update_max_fd(fd);
3549
        rb_fd_set_cloexec(fd);
3551 3550
	ioctl(fd, TIOCNOTTY, NULL);
3552 3551
	close(fd);
3553 3552
    }
......
4838 4837
	err = chdir("/");
4839 4838

  
4840 4839
    if (!noclose && (n = open("/dev/null", O_RDWR, 0)) != -1) {
4841
        rb_update_max_fd(n);
4840
        rb_fd_set_cloexec(n);
4842 4841
	(void)dup2(n, 0);
4843 4842
	(void)dup2(n, 1);
4844 4843
	(void)dup2(n, 2);
ext/pty/pty.c (working copy)
177 177
    {
178 178
        int i = open("/dev/tty", O_RDONLY);
179 179
        if (i < 0) ERROR_EXIT("/dev/tty");
180
        rb_update_max_fd(i);
180
        rb_fd_set_cloexec(i);
181 181
        if (ioctl(i, TIOCNOTTY, (char *)0))
182 182
            ERROR_EXIT("ioctl(TIOCNOTTY)");
183 183
        close(i);
......
199 199
    if (slave < 0) {
200 200
        ERROR_EXIT("open: pty slave");
201 201
    }
202
    rb_update_max_fd(slave);
202
    rb_fd_set_cloexec(slave);
203 203
    close(master);
204 204
#endif
205 205
    dup2(slave,0);
......
291 291
    sigemptyset(&dfl.sa_mask);
292 292

  
293 293
    if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
294
    rb_update_max_fd(masterfd);
294
    rb_fd_set_cloexec(masterfd);
295 295
    if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
296 296
    if (grantpt(masterfd) == -1) goto grantpt_error;
297 297
    if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
......
299 299
    if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
300 300
    if (no_mesg(slavedevice, nomesg) == -1) goto error;
301 301
    if ((slavefd = open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
302
    rb_update_max_fd(slavefd);
302
    rb_fd_set_cloexec(slavefd);
303 303

  
304 304
#if defined I_PUSH && !defined linux
305 305
    if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
......
331 331
	if (!fail) return -1;
332 332
	rb_raise(rb_eRuntimeError, "openpty() failed");
333 333
    }
334
    rb_update_max_fd(*master);
335
    rb_update_max_fd(*slave);
334
    rb_fd_set_cloexec(*master);
335
    rb_fd_set_cloexec(*slave);
336 336
    if (no_mesg(SlaveName, nomesg) == -1) {
337 337
	if (!fail) return -1;
338 338
	rb_raise(rb_eRuntimeError, "can't chmod slave pty");
......
348 348
	if (!fail) return -1;
349 349
	rb_raise(rb_eRuntimeError, "_getpty() failed");
350 350
    }
351
    rb_update_max_fd(*master);
351
    rb_fd_set_cloexec(*master);
352 352

  
353 353
    *slave = open(name, O_RDWR);
354 354
    /* error check? */
355
    rb_update_max_fd(*slave);
355
    rb_fd_set_cloexec(*slave);
356 356
    strlcpy(SlaveName, name, DEVICELEN);
357 357

  
358 358
    return 0;
......
366 366
    extern int grantpt(int);
367 367

  
368 368
    if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
369
    rb_update_max_fd(masterfd);
369
    rb_fd_set_cloexec(masterfd);
370 370
    s = signal(SIGCHLD, SIG_DFL);
371 371
    if(grantpt(masterfd) == -1) goto error;
372 372
    signal(SIGCHLD, s);
......
374 374
    if((slavedevice = ptsname(masterfd)) == NULL) goto error;
375 375
    if (no_mesg(slavedevice, nomesg) == -1) goto error;
376 376
    if((slavefd = open(slavedevice, O_RDWR, 0)) == -1) goto error;
377
    rb_update_max_fd(slavefd);
377
    rb_fd_set_cloexec(slavefd);
378 378
#if defined I_PUSH && !defined linux
379 379
    if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
380 380
    if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
......
398 398
    for (p = deviceNo; *p != NULL; p++) {
399 399
	snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
400 400
	if ((masterfd = open(MasterName,O_RDWR,0)) >= 0) {
401
            rb_update_max_fd(masterfd);
401
            rb_fd_set_cloexec(masterfd);
402 402
	    *master = masterfd;
403 403
	    snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
404 404
	    if ((slavefd = open(SlaveName,O_RDWR,0)) >= 0) {
405
                rb_update_max_fd(slavefd);
405
                rb_fd_set_cloexec(slavefd);
406 406
		*slave = slavefd;
407 407
		if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
408 408
		if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
......
590 590
    wfptr->fd = dup(info.fd);
591 591
    if (wfptr->fd == -1)
592 592
        rb_sys_fail("dup()");
593
    rb_update_max_fd(wfptr->fd);
593
    rb_fd_set_cloexec(wfptr->fd);
594 594
    wfptr->pathv = rfptr->pathv;
595 595

  
596 596
    res = rb_ary_new2(3);
ext/openssl/ossl_bio.c (working copy)
28 28
	if ((fd = dup(FPTR_TO_FD(fptr))) < 0){
29 29
	    rb_sys_fail(0);
30 30
	}
31
        rb_update_max_fd(fd);
31
        rb_fd_set_cloexec(fd);
32 32
	if (!(fp = fdopen(fd, "r"))){
33 33
	    close(fd);
34 34
	    rb_sys_fail(0);
ext/socket/init.c (working copy)
252 252
	}
253 253
    }
254 254
    if (0 <= fd)
255
        rb_update_max_fd(fd);
255
        rb_fd_set_cloexec(fd);
256 256
    return fd;
257 257
}
258 258

  
......
466 466
	}
467 467
        rb_sys_fail("accept(2)");
468 468
    }
469
    rb_update_max_fd(fd2);
469
    rb_fd_set_cloexec(fd2);
470 470
    make_fd_nonblock(fd2);
471 471
    return rsock_init_sock(rb_obj_alloc(klass), fd2);
472 472
}
......
513 513
	}
514 514
	rb_sys_fail(0);
515 515
    }
516
    rb_update_max_fd(fd2);
516
    rb_fd_set_cloexec(fd2);
517 517
    if (!klass) return INT2NUM(fd2);
518 518
    return rsock_init_sock(rb_obj_alloc(klass), fd2);
519 519
}
ext/socket/socket.c (working copy)
119 119
    if (ret < 0) {
120 120
	rb_sys_fail("socketpair(2)");
121 121
    }
122
    rb_update_max_fd(sp[0]);
123
    rb_update_max_fd(sp[1]);
122
    rb_fd_set_cloexec(sp[0]);
123
    rb_fd_set_cloexec(sp[1]);
124 124

  
125 125
    s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
126 126
    s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
ext/socket/ancdata.c (working copy)
1396 1396
        int *end = (int *)((char *)cmh + cmh->cmsg_len);
1397 1397
        while ((char *)fdp + sizeof(int) <= (char *)end &&
1398 1398
               (char *)fdp + sizeof(int) <= msg_end) {
1399
            rb_update_max_fd(*fdp);
1399
            rb_fd_set_cloexec(*fdp);
1400 1400
            close(*fdp);
1401 1401
            fdp++;
1402 1402
        }
......
1439 1439
            VALUE io;
1440 1440
            if (fstat(fd, &stbuf) == -1)
1441 1441
                rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
1442
            rb_update_max_fd(fd);
1442
            rb_fd_set_cloexec(fd);
1443 1443
            if (S_ISSOCK(stbuf.st_mode))
1444 1444
                io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
1445 1445
            else
ext/socket/unixsocket.c (working copy)
383 383
#if FD_PASSING_BY_MSG_CONTROL
384 384
    memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
385 385
#endif
386
    rb_update_max_fd(fd);
386
    rb_fd_set_cloexec(fd);
387 387

  
388 388
    if (klass == Qnil)
389 389
	return INT2FIX(fd);
ext/io/console/console.c (working copy)
562 562
#ifdef CONSOLE_DEVICE_FOR_WRITING
563 563
	fd = open(CONSOLE_DEVICE_FOR_WRITING, O_WRONLY);
564 564
	if (fd < 0) return Qnil;
565
        rb_update_max_fd(fd);
565
        rb_fd_set_cloexec(fd);
566 566
	args[1] = INT2FIX(O_WRONLY);
567 567
	args[0] = INT2NUM(fd);
568 568
	out = rb_class_new_instance(2, args, klass);
......
574 574
#endif
575 575
	    return Qnil;
576 576
	}
577
        rb_update_max_fd(fd);
577
        rb_fd_set_cloexec(fd);
578 578
	args[1] = INT2FIX(O_RDWR);
579 579
	args[0] = INT2NUM(fd);
580 580
	con = rb_class_new_instance(2, args, klass);
ruby.c (working copy)
1527 1527
	if ((fd = open(fname, mode)) < 0) {
1528 1528
	    rb_load_fail(fname);
1529 1529
	}
1530
        rb_update_max_fd(fd);
1530
        rb_fd_set_cloexec(fd);
1531 1531

  
1532 1532
	f = rb_io_fdopen(fd, mode, fname);
1533 1533
    }
test/ruby/test_io.rb (working copy)
1261 1261
  def test_close_on_exec
1262 1262
    skip "IO\#close_on_exec is not implemented." unless have_close_on_exec?
1263 1263
    ruby do |f|
1264
      assert_equal(true, f.close_on_exec?)
1265
      f.close_on_exec = false
1264 1266
      assert_equal(false, f.close_on_exec?)
1265 1267
      f.close_on_exec = true
1266 1268
      assert_equal(true, f.close_on_exec?)
......
1269 1271
    end
1270 1272

  
1271 1273
    with_pipe do |r, w|
1274
      assert_equal(true, r.close_on_exec?)
1275
      r.close_on_exec = false
1272 1276
      assert_equal(false, r.close_on_exec?)
1273 1277
      r.close_on_exec = true
1274 1278
      assert_equal(true, r.close_on_exec?)
1275 1279
      r.close_on_exec = false
1276 1280
      assert_equal(false, r.close_on_exec?)
1277 1281

  
1282
      assert_equal(true, w.close_on_exec?)
1283
      w.close_on_exec = false
1278 1284
      assert_equal(false, w.close_on_exec?)
1279 1285
      w.close_on_exec = true
1280 1286
      assert_equal(true, w.close_on_exec?)
test/ruby/test_process.rb (working copy)
603 603
  def test_fd_inheritance
604 604
    skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows?
605 605
    with_pipe {|r, w|
606
      system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s)
606
      system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s, w=>w)
607 607
      w.close
608 608
      assert_equal("ba\n", r.read)
609 609
    }
......
619 619
	write_file("s", <<-"End")
620 620
	  exec(#{RUBY.dump}, '-e',
621 621
	       'IO.new(ARGV[0].to_i, "w").puts("bu") rescue nil',
622
	       #{w.fileno.to_s.dump})
622
	       #{w.fileno.to_s.dump}, :close_others=>false)
623 623
	End
624
        w.close_on_exec = false
624 625
	Process.wait spawn(RUBY, "s", :close_others=>false)
625 626
	w.close
626 627
	assert_equal("bu\n", r.read)
......
660 661
        File.unlink("err")
661 662
      }
662 663
      with_pipe {|r, w|
664
        w.close_on_exec = false
663 665
        Process.wait spawn(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts("bi")', w.fileno.to_s, :close_others=>false)
664 666
        w.close
665 667
        assert_equal("bi\n", r.read)
......
686 688
        Process.wait
687 689
      }
688 690
      with_pipe {|r, w|
691
        w.close_on_exec = false
689 692
        io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>false])
690 693
        w.close
691 694
        errmsg = io.read
......
694 697
        Process.wait
695 698
      }
696 699
      with_pipe {|r, w|
700
        w.close_on_exec = false
697 701
        io = IO.popen([RUBY, "-e", "STDERR.reopen(STDOUT); IO.new(#{w.fileno}, 'w').puts('mo')", :close_others=>nil])
698 702
        w.close
699 703
        errmsg = io.read
file.c (working copy)
3914 3914
	if ((tmpfd = open(StringValueCStr(path), 0)) < 0) {
3915 3915
	    rb_sys_fail(RSTRING_PTR(path));
3916 3916
	}
3917
        rb_update_max_fd(tmpfd);
3917
        rb_fd_set_cloexec(tmpfd);
3918 3918
	if (chsize(tmpfd, pos) < 0) {
3919 3919
	    close(tmpfd);
3920 3920
	    rb_sys_fail(RSTRING_PTR(path));
......
5062 5062
    int ret = 1;
5063 5063
    int fd = open(path, O_RDONLY);
5064 5064
    if (fd == -1) return 0;
5065
    rb_update_max_fd(fd);
5065
    rb_fd_set_cloexec(fd);
5066 5066
#if !defined DOSISH
5067 5067
    {
5068 5068
	struct stat st;
random.c (working copy)
512 512
            |O_NOCTTY
513 513
#endif
514 514
            )) >= 0) {
515
        rb_update_max_fd(fd);
515
        rb_fd_set_cloexec(fd);
516 516
        if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
517 517
	    if (read(fd, seed, DEFAULT_SEED_LEN) < DEFAULT_SEED_LEN) {
518 518
		/* abandon */;