diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py index c14f836398..5b04c8db37 100644 --- a/dnf/cli/cli.py +++ b/dnf/cli/cli.py @@ -214,7 +214,7 @@ 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(): + if dnf.util.is_bootc_host(): _container_msg = _(""" *** This system is managed with ostree. Changes to the system *** made with dnf will be lost with the next ostree-based update. diff --git a/dnf/util.py b/dnf/util.py index 1b465bda59..0d4b6f432b 100644 --- a/dnf/util.py +++ b/dnf/util.py @@ -644,29 +644,51 @@ def _is_file_pattern_present(specs): def is_container(): + """Returns true if DNF is running in a container, + false otherwise. + """ + # This attempts to reimplement + # https://github.com/ostreedev/ostree-rs-ext/blob/b0d1c1e4748c8708149bb6c92998da623260c4c6/lib/src/container_utils.rs#L20 + # in python. + container_env_var = 'container' + container_env_file = '/run/.containerenv' + docker_env_file = '/.dockerenv' + # https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker + if os.getenv(container_env_var) is not None or os.path.isfile(docker_env_file) or os.path.isfile(container_env_file): + return True + else: + return False + +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. """ - 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) + ostree_booted = '/run/ostree-booted' + usr = '/usr/' - # XXX: the API from bootc status is evolving - status = j.get("status", "") - kind = j.get("kind", "") + # 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). + if os.path.isfile(ostree_booted) and not os.access(usr, os.X_OK): + return True + else: + return False - if kind.lower() == "bootchost" and bool(status.get("isContainer", None)): - return True - elif os.path.isdir(ostree): +def is_bootc_container(): + """Returns true if DNF is running inside a bootc container, + false otherwise. If True, some packages like kernel might be + installed with that in mind. For example only one kernel is + supported on bootc containers and hosts. + ## TODO this is not complete right now as it just checks for + /ostree/ to exists. Also not in use. ## + """ + sysroot_ostree = '/sysroot/ostree' + systemd_env_var = 'INVOCATION_ID' + if is_container() and os.path.exists(sysroot_ostree) and not is_bootc_host() and os.getenv(systemd_env_var) is None: return True + else: + return False - return False