1 /******************************************************************************* 2 3 Global configuration variable to define whether the close-on-exec option 4 should be set on system calls that create a file descriptor in ocean 5 modules. 6 7 On a POSIX system, if a program calls `exec(2)` (or an equivalent function 8 from the `exec` family) to execute another program, then the devices 9 referred to by the file descriptors held by the original program stay open, 10 and the executed program inherits all of them. 11 This has the consequence that, if the executed program is unaware of the 12 original program's file descriptors so it doesn't close those it doesn't 13 need, then all devices will stay open until the process exits. 14 15 Most of the time an `exec` call is preceded by a `fork` call to execute a 16 program in a new process. As with `exec` the child process created by `fork` 17 inherits all file descriptors from its parent process that called `fork`. 18 However, each device referred to by one of these file descriptors stays open 19 until _both_ the parent and child process close them or exit. This means 20 that the parent process has no way of closing its devices any more unless 21 the child process cooperates and does so as well, which is in practice very 22 unlikely. 23 24 This can cause the following situation: 25 - A program opens a device (file, socket, timer or event fd). 26 - The program registers the device with `epoll`. 27 - The program uses a third-party library which starts a task in a separate 28 process using `fork` + `exec`. 29 - The original program (parent process) closes the device. 30 - The executed program (child process) is, as libraries are, unaware of 31 its parent's business so it doesn't close any of the inherited file 32 descriptors; it doesn't even know which it inherited. So the device stays 33 opened. 34 - Because the device is opened it stays registered with `epoll`. The parent 35 process cannot unregister it any more because it has closed the file 36 descriptor. 37 - Until the child process exits `epoll_wait(2)` keeps reporting events for 38 the device in the parent process. 39 40 This is a problem because it can cause sporadic erratic behaviour in a 41 program. The error may be hard to reproduce and track down. 42 43 To prevent this from happening POSIX provides a close-on-exec option for 44 each file descriptor. By default it is disabled. If enabled, `exec` will 45 close the file descriptor so that the executed program won't inherit it. But 46 it works only if the parent process explicitly enables this option for every 47 single file descriptor it obtains from the system. 48 49 The global `open_with_close_on_exec` variable in this module is read by all 50 functions and class constructors in ocean that obtain a file descriptor from 51 the system. If it is `true` then they set the close-on-exec option. 52 53 This does not affect `stdin`, `stdout` and `stderr`, which are opened before 54 the start of the program. 55 56 The flag is `true` by default, which is in general recommended to avoid the 57 aforementioned problem unless file descriptor inheriting is needed, which 58 is not a feature that is currently relevant to Sociomantic's use cases. 59 60 IF YOU HAVE A USE CASE FOR INHERITING FILE DESCRIPTORS, PLEASE CONTACT THE 61 OCEAN MAINTAINERS. 62 63 The following ocean functions obtain a file descriptor and use this flag: 64 65 - `ocean.sys.Epoll`: `Epoll.create` 66 - `ocean.sys.EventFD`: `EventFD` constructor 67 - `ocean.sys.Inotify`: `Inotify` constructor 68 - `ocean.sys.SignalFD`: `SignalFD.register` 69 - `ocean.sys.TimerFD`: `TimerFD` constructor 70 - `ocean.sys.socket`: The `socket` and `accept` methods in all `*Socket` 71 classes 72 - `ocean.io.device.File`: `File.open` 73 74 Copyright: 75 Copyright (c) 2017 dunnhumby Germany GmbH. 76 All rights reserved. 77 78 License: 79 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 80 Alternatively, this file may be distributed under the terms of the Tango 81 3-Clause BSD License (see LICENSE_BSD.txt for details). 82 83 *******************************************************************************/ 84 85 module ocean.sys.CloseOnExec; 86 87 import ocean.meta.types.Qualifiers; 88 89 /******************************************************************************* 90 91 If true then all ocean functions obtaining a file descriptor from the system 92 set the close-on-exec option; if false they don't. Changing the value of 93 this variable does not change the state of previously obtained file 94 descriptors. 95 96 *******************************************************************************/ 97 98 __gshared bool open_with_close_on_exec = true; 99 100 /******************************************************************************* 101 102 Helper function to set the close-on-exec bit in a bit mask which specifies 103 option flags for a system call that obtains a new file descriptor, such as 104 `open(2)`. On recent Linux all such system/library functions support 105 enabling the close-on-exec option; this is a Linux extension to POSIX. Some 106 of these flag accepting functions were added more recently with a name 107 extension, for example `accept4(2)` or `inotify_init1(2)`. 108 109 Params: 110 flags = the flags where the close-on-exec bit should be set if 111 `open_with_close_on_exec` is `true` 112 close_on_exec_flag = a bitmask with only the close-on-exec bit set 113 114 Returns: 115 `flags | close_on_exec_flag` if `open_with_close_on_exec` is `true`, 116 otherwise `flags`. 117 118 *******************************************************************************/ 119 120 T setCloExec ( T, U ) ( T flags, U close_on_exec_flag ) 121 { 122 return open_with_close_on_exec? (flags | close_on_exec_flag) : flags; 123 }