ostree_ext/
container_utils.rs1use std::io;
4use std::io::Read;
5use std::path::Path;
6
7use anyhow::Result;
8use ocidir::cap_std::fs::Dir;
9use ostree::glib;
10
11use crate::keyfileext::KeyFileExt;
12
13pub const OSTREE_BOOTED: &str = "run/ostree-booted";
15
16const V0_REPO_CONFIG: &str = "/sysroot/config";
20const V1_REPO_CONFIG: &str = "/sysroot/ostree/repo/config";
21
22pub fn running_in_container() -> bool {
28 if std::env::var_os("container").is_some() {
29 return true;
30 }
31 for p in ["/run/.containerenv", "/.dockerenv"] {
33 if std::path::Path::new(p).exists() {
34 return true;
35 }
36 }
37 false
38}
39
40pub(crate) fn open_optional(path: impl AsRef<Path>) -> std::io::Result<Option<std::fs::File>> {
43 match std::fs::File::open(path.as_ref()) {
44 Ok(r) => Ok(Some(r)),
45 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
46 Err(e) => Err(e),
47 }
48}
49
50pub fn is_bare_split_xattrs() -> Result<bool> {
53 if let Some(configf) = open_optional(V1_REPO_CONFIG)
54 .transpose()
55 .or_else(|| open_optional(V0_REPO_CONFIG).transpose())
56 {
57 let configf = configf?;
58 let mut bufr = std::io::BufReader::new(configf);
59 let mut s = String::new();
60 bufr.read_to_string(&mut s)?;
61 let kf = glib::KeyFile::new();
62 kf.load_from_data(&s, glib::KeyFileFlags::NONE)?;
63 let r = if let Some(mode) = kf.optional_string("core", "mode")? {
64 mode == crate::tar::BARE_SPLIT_XATTRS_MODE
65 } else {
66 false
67 };
68 Ok(r)
69 } else {
70 Ok(false)
71 }
72}
73
74pub fn ostree_booted() -> io::Result<bool> {
77 Path::new(&format!("/{OSTREE_BOOTED}")).try_exists()
78}
79
80pub fn is_ostree_booted_in(rootfs: &Dir) -> io::Result<bool> {
82 rootfs.try_exists(OSTREE_BOOTED)
83}
84
85pub fn is_ostree_container() -> Result<bool> {
89 let is_container_ostree = is_bare_split_xattrs()?;
90 let running_in_systemd = std::env::var_os("INVOCATION_ID").is_some();
91 let maybe_container = running_in_container() || (!running_in_systemd && !ostree_booted()?);
95 Ok(is_container_ostree && maybe_container)
96}
97
98pub fn require_ostree_container() -> Result<()> {
102 if !is_ostree_container()? {
103 anyhow::bail!("Not in an ostree-based container environment");
104 }
105 Ok(())
106}