1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
//! Library for creating a new process detached from the controling terminal (daemon). //! //! Example: //! ``` //!use fork::{daemon, Fork}; //!use std::process::Command; //! //!if let Ok(Fork::Child) = daemon(false, false) { //! Command::new("sleep") //! .arg("3") //! .output() //! .expect("failed to execute process"); //!} //!``` use std::ffi::CString; use std::process::exit; /// Fork result pub enum Fork { Parent(libc::pid_t), Child, } /// Change dir to `/` [see chdir(2)](https://www.freebsd.org/cgi/man.cgi?query=chdir&sektion=2) /// /// Upon successful completion, 0 shall be returned. Otherwise, -1 shall be /// returned, the current working directory shall remain unchanged, and errno /// shall be set to indicate the error. /// /// Example: /// ///``` ///use fork::chdir; ///use std::env; /// ///match chdir() { /// Ok(_) => { /// let path = env::current_dir().expect("failed current_dir"); /// assert_eq!(Some("/"), path.to_str()); /// } /// _ => panic!(), ///} ///``` /// /// # Errors /// returns `-1` if error pub fn chdir() -> Result<libc::c_int, i32> { let dir = CString::new("/").expect("CString::new failed"); let res = unsafe { libc::chdir(dir.as_ptr()) }; match res { -1 => Err(-1), res => Ok(res), } } /// Close file descriptors stdin,stdout,stderr /// /// # Errors /// returns `-1` if error pub fn close_fd() -> Result<(), i32> { match unsafe { libc::close(0) } { -1 => Err(-1), _ => match unsafe { libc::close(1) } { -1 => Err(-1), _ => match unsafe { libc::close(2) } { -1 => Err(-1), _ => Ok(()), }, }, } } /// Create a new child process [see fork(2)](https://www.freebsd.org/cgi/man.cgi?fork) /// /// Upon successful completion, fork() returns a value of 0 to the child process /// and returns the process ID of the child process to the parent process. /// Otherwise, a value of -1 is returned to the parent process, no child process /// is created. /// /// Example: /// /// ``` ///use fork::{fork, Fork}; /// ///match fork() { /// Ok(Fork::Parent(child)) => { /// println!("Continuing execution in parent process, new child has pid: {}", child); /// } /// Ok(Fork::Child) => println!("I'm a new child process"), /// Err(_) => println!("Fork failed"), ///} ///``` /// This will print something like the following (order indeterministic). /// /// ```text /// Continuing execution in parent process, new child has pid: 1234 /// I'm a new child process /// ``` /// /// The thing to note is that you end up with two processes continuing execution /// immediately after the fork call but with different match arms. /// /// # [`nix::unistd::fork`](https://docs.rs/nix/0.15.0/nix/unistd/fn.fork.html) /// /// The example has been taken from the [`nix::unistd::fork`](https://docs.rs/nix/0.15.0/nix/unistd/fn.fork.html), /// please check the [Safety](https://docs.rs/nix/0.15.0/nix/unistd/fn.fork.html#safety) section /// /// # Errors /// returns `-1` if error pub fn fork() -> Result<Fork, i32> { let res = unsafe { libc::fork() }; match res { -1 => Err(-1), 0 => Ok(Fork::Child), res => Ok(Fork::Parent(res)), } } /// Create session and set process group ID [see setsid(2)](https://www.freebsd.org/cgi/man.cgi?setsid) /// /// Upon successful completion, the setsid() system call returns the value of the /// process group ID of the new process group, which is the same as the process ID /// of the calling process. If an error occurs, setsid() returns -1 /// /// # Errors /// returns `-1` if error pub fn setsid() -> Result<libc::pid_t, i32> { let res = unsafe { libc::setsid() }; match res { -1 => Err(-1), res => Ok(res), } } /// The process group of the current process [see getgrp(2)](https://www.freebsd.org/cgi/man.cgi?query=getpgrp) /// /// # Errors /// returns `-1` if error pub fn getpgrp() -> Result<libc::pid_t, i32> { let res = unsafe { libc::getpgrp() }; match res { -1 => Err(-1), res => Ok(res), } } /// The daemon function is for programs wishing to detach themselves from the /// controlling terminal and run in the background as system daemons. /// /// * `nochdir = false`, changes the current working directory to the root (`/`). /// * `noclose = false`, will close standard input, standard output, and standard error /// /// # Errors /// If an error occurs, returns -1 /// /// Example: /// ///``` ///// The parent forks the child ///// The parent exits ///// The child calls setsid() to start a new session with no controlling terminals ///// The child forks a grandchild ///// The child exits ///// The grandchild is now the daemon ///use fork::{daemon, Fork}; ///use std::process::Command; /// ///if let Ok(Fork::Child) = daemon(false, false) { /// Command::new("sleep") /// .arg("3") /// .output() /// .expect("failed to execute process"); ///} ///``` pub fn daemon(nochdir: bool, noclose: bool) -> Result<Fork, i32> { match fork() { Ok(Fork::Parent(_)) => exit(0), Ok(Fork::Child) => setsid().and_then(|_| { if !nochdir { chdir()?; } if !noclose { close_fd()?; } fork() }), Err(n) => Err(n), } } #[cfg(test)] mod tests { use super::{fork, Fork}; #[test] fn test_fork() { if let Ok(Fork::Parent(child)) = fork() { assert!(child > 0); } } }