1#![allow(unsafe_code)]
2
3use bitflags::bitflags;
4use linux_raw_sys::general::{
5    CLONE_FILES, CLONE_FS, CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID,
6    CLONE_NEWTIME, CLONE_NEWUSER, CLONE_NEWUTS, CLONE_SYSVSEM,
7};
8
9use crate::backend::c::c_int;
10use crate::backend::thread::syscalls;
11use crate::fd::BorrowedFd;
12use crate::io;
13
14bitflags! {
15    /// Thread name space type.
16    pub struct ThreadNameSpaceType: u32 {
17        /// Time name space.
18        const TIME = CLONE_NEWTIME;
19        /// Mount name space.
20        const MOUNT = CLONE_NEWNS;
21        /// Control group (CGroup) name space.
22        const CONTROL_GROUP = CLONE_NEWCGROUP;
23        /// `Host name` and `NIS domain name` (UTS) name space.
24        const HOST_NAME_AND_NIS_DOMAIN_NAME = CLONE_NEWUTS;
25        /// Inter-process communication (IPC) name space.
26        const INTER_PROCESS_COMMUNICATION = CLONE_NEWIPC;
27        /// User name space.
28        const USER = CLONE_NEWUSER;
29        /// Process ID name space.
30        const PROCESS_ID = CLONE_NEWPID;
31        /// Network name space.
32        const NETWORK = CLONE_NEWNET;
33    }
34}
35
36/// Type of name space referred to by a link.
37#[derive(Copy, Clone, Debug, Eq, PartialEq)]
38#[repr(u32)]
39pub enum LinkNameSpaceType {
40    /// Time name space.
41    Time = CLONE_NEWTIME,
42    /// Mount name space.
43    Mount = CLONE_NEWNS,
44    /// Control group (CGroup) name space.
45    ControlGroup = CLONE_NEWCGROUP,
46    /// `Host name` and `NIS domain name` (UTS) name space.
47    HostNameAndNISDomainName = CLONE_NEWUTS,
48    /// Inter-process communication (IPC) name space.
49    InterProcessCommunication = CLONE_NEWIPC,
50    /// User name space.
51    User = CLONE_NEWUSER,
52    /// Process ID name space.
53    ProcessID = CLONE_NEWPID,
54    /// Network name space.
55    Network = CLONE_NEWNET,
56}
57
58bitflags! {
59    /// `CLONE_*` for use with [`unshare`].
60    pub struct UnshareFlags: u32 {
61        /// `CLONE_FILES`.
62        const FILES = CLONE_FILES;
63        /// `CLONE_FS`.
64        const FS = CLONE_FS;
65        /// `CLONE_NEWCGROUP`.
66        const NWCGROUP = CLONE_NEWCGROUP;
67        /// `CLONE_NEWIPC`.
68        const NEWIPC = CLONE_NEWIPC;
69        /// `CLONE_NEWNET`.
70        const NEWNET = CLONE_NEWNET;
71        /// `CLONE_NEWNS`.
72        const NEWNS = CLONE_NEWNS;
73        /// `CLONE_NEWPID`.
74        const NEWPID = CLONE_NEWPID;
75        /// `CLONE_NEWTIME`.
76        const NEWTIME = CLONE_NEWTIME;
77        /// `CLONE_NEWUSER`.
78        const NEWUSER = CLONE_NEWUSER;
79        /// `CLONE_SYSVSEM`.
80        const SYSVSEM = CLONE_SYSVSEM;
81    }
82}
83
84/// Reassociate the calling thread with the namespace associated with link referred to by `fd`.
85///
86/// `fd` must refer to one of the magic links in a `/proc/[pid]/ns/` directory, or a bind mount
87/// to such a link.
88///
89/// # References
90/// - [`setns`]
91///
92/// [`setns`]: https://man7.org/linux/man-pages/man2/setns.2.html
93pub fn move_into_link_name_space(
94    fd: BorrowedFd,
95    allowed_type: Option<LinkNameSpaceType>,
96) -> io::Result<()> {
97    let allowed_type = allowed_type.map_or(0, |t| t as c_int);
98    syscalls::setns(fd, allowed_type).map(|_r| ())
99}
100
101/// Atomically move the calling thread into one or more of the same namespaces as the thread
102/// referred to by `fd`.
103///
104/// `fd` must refer to a thread ID. See: `pidfd_open` and `clone`.
105///
106/// # References
107/// - [`setns`]
108///
109/// [`setns`]: https://man7.org/linux/man-pages/man2/setns.2.html
110pub fn move_into_thread_name_spaces(
111    fd: BorrowedFd,
112    allowed_types: ThreadNameSpaceType,
113) -> io::Result<()> {
114    syscalls::setns(fd, allowed_types.bits() as c_int).map(|_r| ())
115}
116
117/// `unshare(flags)`—Disassociate parts of the current thread's execution
118/// context with other threads.
119///
120/// # References
121/// - [`unshare`]
122///
123/// [`unshare`]: https://man7.org/linux/man-pages/man2/unshare.2.html
124pub fn unshare(flags: UnshareFlags) -> io::Result<()> {
125    syscalls::unshare(flags)
126}
127