From af8b8297f0b8e990b81eeb7f5022c2d3b6ef0dd9 Mon Sep 17 00:00:00 2001
From: Joseph Marrero <jmarrero@redhat.com>
Date: Tue, 16 Jul 2024 15:48:41 -0400
Subject: [PATCH] Update ostree/bootc host system check.

This changes the is_container() func for is_bootc_host()
and updates the logic and message. This should detect on
all ostree and bootc hosts to date that are not using
bootc usroverlay or ostree admin unlock for development
purposes.

resolves: #RHEL-49670, RHEL-49671
---
 dnf/cli/cli.py | 11 +++++------
 dnf/util.py    | 30 ++++++++----------------------
 2 files changed, 13 insertions(+), 28 deletions(-)

diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py
index c14f836398..61420df884 100644
--- a/dnf/cli/cli.py
+++ b/dnf/cli/cli.py
@@ -214,13 +214,12 @@ def do_transaction(self, display=()):
             elif 'test' in self.conf.tsflags:
                 logger.info(_("{prog} will only download packages, install gpg keys, and check the "
                               "transaction.").format(prog=dnf.util.MAIN_PROG_UPPER))
-            if dnf.util.is_container():
-                _container_msg = _("""
-*** This system is managed with ostree.  Changes to the system
-*** made with dnf will be lost with the next ostree-based update.
-*** If you do not want to lose these changes, use 'rpm-ostree'.
+            if dnf.util.is_bootc_host():
+                _bootc_host_msg = _("""
+*** error: system is configured to be read-only; for more
+*** information run `bootc status` or `ostree admin status`.
 """)
-                logger.info(_container_msg)
+                logger.info(_bootc_host_msg)
                 raise CliError(_("Operation aborted."))
 
             if self._promptWanted():
diff --git a/dnf/util.py b/dnf/util.py
index 1b465bda59..3f5a5c10a2 100644
--- a/dnf/util.py
+++ b/dnf/util.py
@@ -643,30 +643,16 @@ def _is_file_pattern_present(specs):
     return False
 
 
-def is_container():
+def is_bootc_host():
     """Returns true is the system is managed as an immutable container,
        false otherwise.  If msg is True, a warning message is displayed
        for the user.
     """
+    ostree_booted = '/run/ostree-booted'
+    usr = '/usr/'
+    # Check if usr is writtable and we are in a running ostree system.
+    # We want this code to return true only when the system is in locked state. If someone ran
+    # bootc overlay or ostree admin unlock we would want normal DNF path to be ran as it will be
+    # temporary changes (until reboot).
+    return os.path.isfile(ostree_booted) and not os.access(usr, os.W_OK)
 
-    bootc = '/usr/bin/bootc'
-    ostree = '/sysroot/ostree'
-
-    if os.path.isfile(bootc) and os.access(bootc, os.X_OK):
-        p = subprocess.Popen([bootc, "status", "--json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        (out, err) = p.communicate()
-
-        if p.returncode == 0:
-            # check the output of 'bootc status'
-            j = json.loads(out)
-
-            # XXX: the API from bootc status is evolving
-            status = j.get("status", "")
-            kind = j.get("kind", "")
-
-            if kind.lower() == "bootchost" and bool(status.get("isContainer", None)):
-                return True
-    elif os.path.isdir(ostree):
-        return True
-
-    return False