fork-0.1.22/.cargo_vcs_info.json0000644000000001360000000000100120570ustar { "git": { "sha1": "f32e4bae4898dcababfafa946038276edf2a42dd" }, "path_in_vcs": "" }fork-0.1.22/.github/FUNDING.yml000064400000000000000000000000161046102023000140210ustar 00000000000000github: nbari fork-0.1.22/.github/workflows/ci.yml000064400000000000000000000026631046102023000153710ustar 00000000000000name: ci on: [push] env: CARGO_TERM_COLOR: always jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: check test: name: Test Suite runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: test fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add rustfmt - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add clippy - uses: actions-rs/cargo@v1 with: command: clippy args: -- -D clippy::all -D clippy::nursery -D warnings fork-0.1.22/.gitignore000064400000000000000000000000371046102023000126370ustar 00000000000000/target/ Cargo.lock **/*.rs.bk fork-0.1.22/.travis.yml000064400000000000000000000004671046102023000127670ustar 00000000000000language: rust rust: - stable - beta os: - linux - osx before_script: - rustup component add clippy script: - cargo clippy --all-targets --all-features -- -D clippy::pedantic -D clippy::nursery - cargo build --all --all-targets - cargo test --all notifications: email: on_sucess: never fork-0.1.22/Cargo.toml0000644000000021330000000000100100540ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "fork" version = "0.1.22" authors = ["Nicolas Embriz "] description = "Library for creating a new process detached from the controlling terminal (daemon)" homepage = "https://docs.rs/fork/latest/fork/" documentation = "https://docs.rs/fork/latest/fork/" readme = "README.md" keywords = [ "fork", "setsid", "daemon", "process", "daemonize", ] categories = [ "command-line-utilities", "os", ] license = "BSD-3-Clause" repository = "https://github.com/immortal/fork" [dependencies.libc] version = "0.2" [badges.travis-ci] branch = "master" repository = "immortal/fork" fork-0.1.22/Cargo.toml.orig000064400000000000000000000011451046102023000135370ustar 00000000000000[package] name = "fork" version = "0.1.22" authors = ["Nicolas Embriz "] description = "Library for creating a new process detached from the controlling terminal (daemon)" documentation = "https://docs.rs/fork/latest/fork/" homepage = "https://docs.rs/fork/latest/fork/" repository = "https://github.com/immortal/fork" readme = "README.md" keywords = ["fork", "setsid", "daemon", "process", "daemonize"] categories = ["command-line-utilities", "os"] license = "BSD-3-Clause" edition = "2018" [badges] travis-ci = { repository = "immortal/fork", branch = "master" } [dependencies] libc = "0.2" fork-0.1.22/LICENSE000064400000000000000000000027541046102023000116640ustar 00000000000000BSD 3-Clause License Copyright (c) 2019, immortal All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. fork-0.1.22/README.md000064400000000000000000000040041046102023000121240ustar 00000000000000# fork [![crates.io](https://img.shields.io/crates/v/fork.svg)](https://crates.io/crates/fork) [![Build Status](https://travis-ci.org/immortal/fork.svg?branch=master)](https://travis-ci.org/immortal/fork) [![docs](https://docs.rs/fork/badge.svg)](https://docs.rs/fork) Library for creating a new process detached from the controlling terminal (daemon). ## Why? - Minimal library to daemonize, fork, double-fork a process. - [daemon(3)](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/daemon.3.html) has been deprecated in MacOSX 10.5, by using `fork` and `setsid` syscalls, new methods can be created to achieve the same goal. Example: Create a new test project: $ cargo new --bin fork > To install `cargo` use: `curl https://sh.rustup.rs -sSf | sh` Edit `fork/Cargo.toml` and add to `[dependencies]`: fork = "0.1" Add the following code to `fork/main.rs` ```rs use fork::{daemon, Fork}; use std::process::Command; fn main() { if let Ok(Fork::Child) = daemon(false, false) { Command::new("sleep") .arg("300") .output() .expect("failed to execute process"); } } ``` > If using `daemon(false, false)`,it will `chdir` to `/` and close the standard input, standard output, and standard error file descriptors. Test running: $ cargo run Use `ps` to check the process, for example: $ ps -axo ppid,pid,pgid,sess,tty,tpgid,stat,uid,%mem,%cpu,command, | egrep "fork|sleep|PID" > `egrep` is used to show the `ps` headers Output should be something like: ```pre PPID PID PGID SESS TTY TPGID STAT UID %MEM %CPU COMMAND 1 48738 48737 0 ?? 0 S 501 0.0 0.0 target/debug/fork 48738 48753 48737 0 ?? 0 S 501 0.0 0.0 sleep 300 ``` * `PPID == 1` that's the parent process * `TTY = ??` no controlling terminal * new `PGID = 48737` 1 - root (init/launchd) \-- 48738 fork PGID - 48737 \--- 48753 sleep PGID - 48737 fork-0.1.22/src/lib.rs000064400000000000000000000127301046102023000125550ustar 00000000000000//! Library for creating a new process detached from the controlling 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 { 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 { 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 { 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 { 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 { 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); } } }