pg_embedded_setup_unpriv/bootstrap/
mode.rs

1//! Detects execution privileges and selects the appropriate orchestration mode.
2
3use camino::Utf8PathBuf;
4
5use crate::error::{BootstrapError, BootstrapResult};
6
7#[cfg(unix)]
8use nix::unistd::geteuid;
9
10/// Represents the privileges the process is running with when bootstrapping `PostgreSQL`.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ExecutionPrivileges {
13    /// The process owns `root` privileges and must drop to `nobody` for filesystem work.
14    Root,
15    /// The process is already unprivileged, so bootstrap tasks run with the current UID/GID.
16    Unprivileged,
17}
18
19/// Selects how `PostgreSQL` lifecycle commands run when privileged execution is required.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ExecutionMode {
22    /// Execute lifecycle commands directly within the current process.
23    ///
24    /// This mode is only appropriate when the process already runs without elevated privileges.
25    InProcess,
26    /// Delegate lifecycle commands to a helper subprocess executed with reduced privileges.
27    Subprocess,
28}
29
30#[must_use]
31pub fn detect_execution_privileges() -> ExecutionPrivileges {
32    #[cfg(unix)]
33    {
34        if geteuid().is_root() {
35            ExecutionPrivileges::Root
36        } else {
37            ExecutionPrivileges::Unprivileged
38        }
39    }
40
41    #[cfg(not(unix))]
42    {
43        ExecutionPrivileges::Unprivileged
44    }
45}
46
47pub(super) fn determine_execution_mode(
48    privileges: ExecutionPrivileges,
49    worker_binary: Option<&Utf8PathBuf>,
50) -> BootstrapResult<ExecutionMode> {
51    #[cfg(unix)]
52    {
53        match privileges {
54            ExecutionPrivileges::Root => {
55                if worker_binary.is_none() {
56                    Err(BootstrapError::from(color_eyre::eyre::eyre!(
57                        "PG_EMBEDDED_WORKER must be set when running with root privileges"
58                    )))
59                } else {
60                    Ok(ExecutionMode::Subprocess)
61                }
62            }
63            ExecutionPrivileges::Unprivileged => Ok(ExecutionMode::InProcess),
64        }
65    }
66
67    #[cfg(not(unix))]
68    {
69        let _ = worker_binary;
70        let _ = privileges;
71        Ok(ExecutionMode::InProcess)
72    }
73}