1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
daemonize.rs 6 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
ace yan Отправлено 3 лет назад 4df5013
// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
#![deny(missing_docs)]
//! This file implements a high level wrapper for daemonize
//!
//! # Daemonize Introduction
//!
//! [daemonize](https://linux.die.net/man/1/daemonize) to runs a command as a
//! Unix daemonize. A daemon is a process that executes in the background either
//! waiting for some event to occur, or waiting to perform some specified task
//! on a periodic basis. A typical daemon program will:
//! 1. Close all open file descriptors(especially standard input, standard
//! output and standard error).
//! 2. Change its working directory to the root filesystem, to ensure that it
//! doesn't tie up another filesystem and prevent it from being unmounted.
//! 3. Reset its umask value.
//! 4. Run in the background(i.e., fork).
//! 5. Ignore all terminal I/O signals.
//! 6. Disassociate from the control terminal.
//! 7. Disassociate from its process group, to insulate itself from signals
//! sent to the process group.
//! 8. Handle any `SIGCLD` signals.
use std::cmp::Ordering;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::RawFd;
use std::path::Path;
use std::process::exit;
use crate::errors::{ErrorKind, Result};
/// Write process id to pid file.
fn create_pid_file(path: &str) -> Result<()> {
let pid: u32 = std::process::id();
let mut pid_file: File = OpenOptions::new()
.write(true)
.create(true)
.mode(0o600)
.open(path)?;
write!(pid_file, "{}", pid)?;
Ok(())
}
/// [fork(2)](https://man7.org/linux/man-pages/man2/fork.2.html)
/// fork() creates a new process by duplicating the calling process. The new
/// process is referred to as the child process. The calling process is referred
/// to as the parent process.
/// **libc::fork()** may have three kinds ret:
/// if ret > 0 : current process is parent process, it's not expected, so exit
/// if ret < 0 : error occurred in fork()
/// if ret = 0 : current process is child process, it's expected
///
/// # Errors
///
/// `DaemonFork` Error, the ret of `libc::fork()` is less than zero.
fn fork() -> Result<()> {
let ret = unsafe { libc::fork() };
match ret.cmp(&0) {
Ordering::Less => Err(ErrorKind::DaemonFork.into()),
Ordering::Greater => exit(0),
Ordering::Equal => Ok(()),
}
}
/// [setsid(2)](https://man7.org/linux/man-pages/man2/setsid.2.html)
/// setsid() creates a new session if the calling process is not a process group
/// leader. The calling process is the leader of the new session. The calling
/// process also becomes the process group leader or a new process group in the
/// session.
/// The calling process will be the only process in the new process group and in
/// the new session. New session has no controlling termimal.
///
/// # Errors
///
/// `DaemonSetsid` Error, the ret of `libc::setsid()` is -1
fn set_sid() -> Result<()> {
let ret = unsafe { libc::setsid() };
if ret == -1 {
Err(ErrorKind::DaemonSetsid.into())
} else {
Ok(())
}
}
/// Redirect stdio to `/dev/null`.
///
/// Use [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)
/// dup2(oldfd, newfd) creates a copy of the file descriptor `oldfd`, uses the
/// file descriptor number specified in `newfd`. If the file descriptor `newfd`
/// was previously open, it is silently closed before being reused. This
/// function use `dup2` to redirect file descriptor use to `/dev/null`.
///
/// # Errors
///
/// `DaemonRedirectStdio` Error, the ret of `libc::open()`, `libc::dup2()`,
/// `libc::close()`is -1
fn redirect_stdio(fd: RawFd) -> Result<()> {
unsafe {
let devnull_fd = libc::open(b"/dev/null\0" as *const [u8; 10] as _, libc::O_RDWR);
if devnull_fd == -1 {
return Err(ErrorKind::DaemonRedirectStdio.into());
}
if libc::dup2(devnull_fd, fd) == -1 {
return Err(ErrorKind::DaemonRedirectStdio.into());
}
if libc::close(devnull_fd) == -1 {
return Err(ErrorKind::DaemonRedirectStdio.into());
}
}
Ok(())
}
/// Daemonize a process.
///
/// # Arguments
///
/// * `pid_file` - Path where will create pid file.
///
/// # Notes
/// This function do five things to daemonize a process:
/// 1. Reset its umask value.
/// 2. Run in the background use fork.
/// 3. Ignore all terminal I/O signals.
/// 4. Disassociate from the control terminal.
/// 5. Write pid to pidfile.
pub fn daemonize(pid_file: Option<String>) -> Result<()> {
if let Some(path) = pid_file.as_ref() {
if Path::new(path).exists() {
return Err(ErrorKind::PidFileExist.into());
}
}
// The first fork make parent process quit, child process inherit parent's
// session ID and have a new process ID. It can guarantee child
// process will not be the first process in a session.
fork()?;
// Create a new session for process. Now parent process quit will not
// influence stratovirt process. But stratovirt becomes the first process in
// new section.
set_sid()?;
// The second fork make stratovirt run as daemonize process. It won't be the
// first process in this session and never get terminal control.
fork()?;
// Redirect stdio to `/dev/null`.
redirect_stdio(libc::STDIN_FILENO)?;
redirect_stdio(libc::STDOUT_FILENO)?;
redirect_stdio(libc::STDERR_FILENO)?;
// Now can record PID to file. It won't be changed again in stratovirt's
// lifetime.
if let Some(path) = pid_file {
create_pid_file(&path)?;
}
Ok(())
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v2.2.0-rc1