diff --git a/iridium_installer/backend/os_install.py b/iridium_installer/backend/os_install.py index dbf3af1..49828fb 100644 --- a/iridium_installer/backend/os_install.py +++ b/iridium_installer/backend/os_install.py @@ -110,10 +110,117 @@ def mount_pseudo_fs(mount_root): logger.warning(f"Failed to unmount {path}: {e}") -def install_minimal_os(mount_root, releasever="43"): +def has_rpms(path): + """Checks if a directory contains any .rpm files.""" + if not os.path.isdir(path): + return False + try: + for f in os.listdir(path): + if f.endswith(".rpm"): + return True + except Exception: + pass + return False + + +def find_iso_repo(): + """ + Attempts to find a local repository on the ISO or other mounted media. + """ + possible_paths = [ + "/run/install/repo", + "/run/install/source", + "/mnt/install/repo", + "/run/initramfs/live", + "/run/initramfs/isoscan", + ] + + # 1. Check known paths for repodata or media.repo + for path in possible_paths: + if os.path.exists(os.path.join(path, "repodata")) or os.path.exists(os.path.join(path, "media.repo")): + return path + for sub in ["os", "Packages", "BaseOS", "AppStream"]: + sub_path = os.path.join(path, sub) + if os.path.exists(os.path.join(sub_path, "repodata")) or os.path.exists(os.path.join(sub_path, "media.repo")): + return sub_path + + # 2. Check all mounted filesystems + try: + res = subprocess.run(["findmnt", "-nlo", "TARGET"], capture_output=True, text=True) + if res.returncode == 0: + for mount in res.stdout.splitlines(): + if mount.startswith("/proc") or mount.startswith("/sys") or mount.startswith("/dev"): + continue + if os.path.exists(os.path.join(mount, "repodata")) or os.path.exists(os.path.join(mount, "media.repo")): + return mount + for sub in ["os", "Packages", "BaseOS", "AppStream"]: + if os.path.exists(os.path.join(mount, sub, "repodata")) or os.path.exists(os.path.join(mount, sub, "media.repo")): + return os.path.join(mount, sub) + except Exception as e: + logger.debug(f"Error searching mount points: {e}") + + # 3. Try to mount /dev/sr0 or /dev/cdrom if not already mounted + for dev in ["/dev/sr0", "/dev/cdrom"]: + try: + if os.path.exists(dev): + res = subprocess.run(["findmnt", "-n", dev], capture_output=True) + if res.returncode != 0: + logger.info(f"Found {dev} but not mounted. Attempting to mount to /mnt...") + try: + subprocess.run(["mount", "-o", "ro", dev, "/mnt"], check=True) + if os.path.exists("/mnt/repodata") or os.path.exists("/mnt/media.repo"): + return "/mnt" + for sub in ["os", "Packages", "BaseOS", "AppStream"]: + if os.path.exists(os.path.join("/mnt", sub, "repodata")) or os.path.exists(os.path.join("/mnt", sub, "media.repo")): + return os.path.join("/mnt", sub) + except Exception as e: + logger.debug(f"Failed to mount {dev}: {e}") + except Exception: + pass + + # 4. Check /run/media + if os.path.exists("/run/media"): + try: + for user in os.listdir("/run/media"): + user_path = os.path.join("/run/media", user) + if os.path.isdir(user_path): + for label in os.listdir(user_path): + label_path = os.path.join(user_path, label) + if os.path.exists(os.path.join(label_path, "repodata")) or os.path.exists(os.path.join(label_path, "media.repo")): + return label_path + for sub in ["os", "Packages", "BaseOS", "AppStream"]: + if os.path.exists(os.path.join(label_path, sub, "repodata")) or os.path.exists(os.path.join(label_path, sub, "media.repo")): + return os.path.join(label_path, sub) + except Exception: + pass + + # 5. Last resort: any directory with .rpm files + for path in possible_paths: + if has_rpms(path): return path + for sub in ["os", "Packages", "BaseOS", "AppStream"]: + if has_rpms(os.path.join(path, sub)): return os.path.join(path, sub) + + return None + + +def install_minimal_os(mount_root, releasever=None): """ Installs minimal Fedora packages to mount_root. """ + if not releasever: + # Try to detect from host + try: + with open("/etc/os-release", "r") as f: + for line in f: + if line.startswith("VERSION_ID="): + releasever = line.split("=")[1].strip().strip('"') + break + except Exception: + pass + + if not releasever: + releasever = "43" # Fallback + logger.info(f"Installing minimal Fedora {releasever} to {mount_root}...") log_os_install("INSTALL", "start", f"Target: {mount_root}, Release: {releasever}") @@ -134,36 +241,7 @@ def install_minimal_os(mount_root, releasever="43"): ] # Offline installation logic - possible_repos = [ - "/run/install/repo", - "/run/install/source", - "/mnt/install/repo", - "/run/initramfs/live", - "/run/initramfs/isoscan", - ] - - iso_repo = None - for path in possible_repos: - if os.path.exists(os.path.join(path, "repodata")): - iso_repo = path - break - elif os.path.exists(os.path.join(path, "Packages")): - iso_repo = path - break - - # Try searching in /run/media if not found - if not iso_repo and os.path.exists("/run/media"): - try: - for user in os.listdir("/run/media"): - user_path = os.path.join("/run/media", user) - if os.path.isdir(user_path): - for label in os.listdir(user_path): - label_path = os.path.join(user_path, label) - if os.path.exists(os.path.join(label_path, "repodata")): - iso_repo = label_path - break - if iso_repo: break - except Exception: pass + iso_repo = find_iso_repo() dnf_args = [] if iso_repo: @@ -172,10 +250,19 @@ def install_minimal_os(mount_root, releasever="43"): "--disablerepo=*", f"--repofrompath=iridium-iso,{iso_repo}", "--enablerepo=iridium-iso", + "--nogpgcheck", "--cacheonly", + "--setopt=iridium-iso.gpgcheck=0", + "--setopt=metadata_expire=-1", ] else: - logger.warning("ISO repository not found in common locations. DNF might try to use network.") + # Check if we are on a Live ISO but no repo found + if os.path.exists("/run/initramfs/live/LiveOS/squashfs.img"): + logger.warning("Detected Fedora Live environment, but no RPM repository was found on the media.") + logger.warning("Workstation Live ISOs usually do not contain a DNF repository for offline installation.") + logger.warning("Consider using an 'Everything' or 'Server' ISO for offline package-based install.") + + logger.warning("ISO repository not found. DNF will attempt to use network.") dnf_args = [] cmd = [