def manage_uefi_files(_os, mount_point): """Manage UEFI bootloader files.""" logger.info("manage_uefi_files(): Copying UEFI Files to uefi_boot_dir...") #First, let's check if EFI/boot already exists. This is a fat32/fat16 filesystem, #so case doesn't matter. if os.path.isdir(mount_point+"/boot/efi/EFI/boot"): uefi_boot_dir = mount_point+"/boot/efi/EFI/boot" else: #It doesn't, so we'll create it. uefi_boot_dir = mount_point+"/boot/efi/EFI/boot" CoreTools.start_process("mkdir "+uefi_boot_dir, show_output=False, privileged=True) #Do this different depending on whether the OS is ubuntu or fedora-based. if OS_INFO[_os]["PackageManager"] == "apt-get": source_dir = mount_point+"/boot/efi/EFI/ubuntu" elif OS_INFO[_os]["PackageManager"] == "dnf": source_dir = mount_point+"/boot/efi/EFI/fedora" if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB-UEFI": #We need to copy grubx64.efi to uefi_boot_dir. logger.info("manage_uefi_files(): Copying grubx64.efi to "+uefi_boot_dir+"...") if CoreTools.start_process("cp -v "+source_dir+"/grubx64.efi "+uefi_boot_dir+"/bootx64.efi", show_output=False, privileged=True) != 0: logger.error("manage_uefi_files(): Failed to copy "+source_dir+"/grub*.efi to " + uefi_boot_dir+"/bootx64.efi! Attempting to continue anyway...") logger.info("manage_uefi_files(): Done!")
def test_start_process(self): for command in self.commands: retval, output = CoreTools.start_process(command, return_output=True, testing=True) self.assertEqual(retval, self.commands[command]["Retval"]) self.assertEqual(output, self.commands[command]["Output"])
def check_depends(): """ Check dependencies, and show an error message and kill the app if the dependencies are not met. """ logger.info("MainStartupTools(): check_depends(): Checking dependencies...") #Create a temporary list to allow WxFixBoot to notify the user of particular unmet #dependencies. TODO This will need to be updated at each release time. cmd_list = ("mkdir", "notify-send", "pkexec", "cp", "mv", "which", "uname", "fsck", "ls", "modprobe", "mount", "umount", "rm", "ping", "badblocks", "arch", "file", "sh", "echo", "dmidecode", "chroot", "strings", "dd", "dmsetup") #Create a list to contain names of failed commands. failed_list = [] for cmd in cmd_list: #Run the command with its argument and log the output (if in debug mode) retval, output = CoreTools.start_process("which "+cmd, return_output=True) if retval != 0: logger.error("check_depends(): Dependency problems! Command: "+cmd + " failed to execute or wasn't found.") logger.error("check_depends(): The error was: "+output) failed_list.append(cmd) #Check if any commands failed. if failed_list != []: #Missing dependencies! logger.critical("check_depends(): Dependencies missing! WxFixBoot will exit. The missing " + "dependencies are: "+', '.join(failed_list)+". Exiting.") CoreTools.emergency_exit("The following dependencies could not be found on your system: " + ', '.join(failed_list)+".\n\nPlease install the missing " + "dependencies.") #Check that the getdevinfo version is 1.0.10 or greater. version_okay = False #TODO May need to change before each release. versions = ["1.1.1", getdevinfo.getdevinfo.VERSION] #Last entry is highest version. versions = sorted(versions, key=LooseVersion) if versions[-1] == versions[-2]: #This is the latest version WxFixBoot is aware of at the time of writing. version_okay = True elif versions[-1] != "1.1.1" and versions[-1] == getdevinfo.getdevinfo.VERSION: #This is newer than the latest version WxFixBoot is aware of at the time of writing. version_okay = True if not version_okay: logger.critical("check_depends(): Your getdevinfo module is known to not work with this " + "version of WxFixBoot. Please update to at least 1.1.1") CoreTools.emergency_exit("Your getdevinfo module is known to not work " + "with this version of WxFixBoot. Please update to at least " + "v1.1.1.")
def find_missing_fsck_modules(): """Check for and return all missing fsck modules (fsck.vfat, fsck.minix, etc).""" logger.info("find_missing_fsck_modules(): Looking for missing FSCK modules to ignore...") failed_list = [] keys = list(DISK_INFO.keys()) keys.sort() for disk in keys: #Check the FSType is known and isn't swap. if DISK_INFO[disk]["FileSystem"] not in ("Unknown", "N/A"): #Check if this module is present. if CoreTools.start_process("which fsck."+DISK_INFO[disk]["FileSystem"], show_output=False) != 0: #Couldn't find it, add it to the failed list. logger.warning("FSCKModules(): Couldn't find FSCK module fsck." + DISK_INFO[disk]["FileSystem"] + "! Adding it to the list of missing modules...") failed_list.append("fsck."+DISK_INFO[disk]["FileSystem"]) else: logger.debug("FSCKModules(): Found fsck."+DISK_INFO[disk]["FileSystem"]+"...") #Return the list, so FSCheck functions know which FSes to ignore. logger.info("find_missing_fsck_modules(): Done! Missing FSCK modules: "+', '.join(failed_list)) return failed_list
def check_depends(): """ Check dependencies, and show an error message and kill the app if the dependencies are not met. """ #Create a temporary list to allow WxFixBoot to notify the user of particular unmet #dependencies. cmd_list = ("cp", "mv", "which", "uname", "fsck", "ls", "modprobe", "mount", "umount", "rm", "ping", "badblocks", "arch", "file", "sh", "echo", "lshw", "lvdisplay", "dmidecode", "chroot", "strings", "dd", "blkid") #Create a list to contain names of failed commands. failed_list = [] for command in cmd_list: #Run the command with its argument and log the output (if in debug mode) retval = CoreTools.start_process("which "+command, return_output=True)[0] if retval != 0: failed_list.append(command) #Check if any commands failed. if failed_list != []: #Missing dependencies! emergency_exit("The following dependencies could not be found on your system: " + ', '.join(failed_list)+".\n\nPlease install the missing dependencies.")
def check_filesystems(): """Check all unmounted filesystems.""" logger.info("check_filesystems(): Checking filesystems if possible. Running 'fsck -ARMp'...") if CoreTools.start_process("fsck -ARMp", privileged=True) not in (0, 8): logger.critical("check_filesystems(): Failed to check filesystems! Doing emergency " + "exit...") CoreTools.emergency_exit("Failed to check filesystems! Please fix your filesystems " + "and then run WxFixBoot again.")
def get_firmware_type(): """Get the firmware type""" #Check if the firmware type is UEFI. #Also, look for UEFI variables. #Make sure efivars module is loaded. If it doesn't exist, continue anyway. CoreTools.start_process("modprobe efivars", privileged=True) #Look for the UEFI vars in some common directories. if os.path.isdir("/sys/firmware/efi/vars") \ and CoreTools.start_process("ls /sys/firmware/efi/vars", return_output=True)[1] != "": uefi_variables = True logger.info("get_firmware_type(): Found UEFI Variables at /sys/firmware/efi/vars...") elif os.path.isdir("/proc/efi/vars") \ and CoreTools.start_process("ls /proc/efi/vars", return_output=True)[1] != "": uefi_variables = True logger.info("get_firmware_type(): Found UEFI Variables at /proc/efi/vars...") elif os.path.isdir("/sys/firmware/efi/efivars") \ and CoreTools.start_process("ls /sys/firmware/efi/efivars", return_output=True)[1] != "": uefi_variables = True logger.info("get_firmware_type(): Found UEFI Variables at /sys/firmware/efi/efivars...") else: logger.info("get_firmware_type(): UEFI vars not found in /sys/firmware/efi/vars, " + "/sys/firmware/efi/efivars, or /proc/efi/vars. This is normal if running " + "on a BIOS system. Determining firmware type a different way...") uefi_variables = False if uefi_variables: #It's UEFI. logger.info("get_firmware_type(): Detected Firmware Type as UEFI.") SYSTEM_INFO["FirmwareType"] = "UEFI" else: #Look a second way. output = CoreTools.start_process("dmidecode -q -t BIOS", return_output=True, privileged=True)[1] if "UEFI" not in output: #It's BIOS. logger.info("get_firmware_type(): Detected Firmware Type as BIOS...") SYSTEM_INFO["FirmwareType"] = "BIOS" else: #It's UEFI. logger.warning("get_firmware_type(): Detected Firmware Type as UEFI, but couldn't " + "find UEFI variables!") SYSTEM_INFO["FirmwareType"] = "UEFI" DialogTools.show_msg_dlg(kind="warning", message="Your computer uses UEFI firmware, " + "but the UEFI variables couldn't be mounted or weren't " + "found. Please ensure you've booted in UEFI mode rather " + "than legacy mode to enable access to the UEFI variables. " + "You can attempt installing a UEFI bootloader without " + "them, but it might not work, and it isn't recommended.")
def wait_until_packagemanager_free(mount_point, package_manager): """ Check if the package manager is in use, and if so, wait until it is no longer in use. """ if package_manager == "apt-get": cmd = "apt-get check" success_retvals = (0, 0) #100 omitted - indicates apt is in use. elif package_manager == "dnf": cmd = "dnf -C check-update" success_retvals = (0, 100) #100 - updates available. if mount_point != "": cmd = "chroot "+mount_point+" "+cmd retval = 1 #Trap in while loop until package manager is free. #FIXME: Doesn't work with DNF, but doesn't strictly matter because it will just wait #FIXME: Handle return code 100 when updates are available. #until the lock is free, rather than exiting. while retval not in success_retvals: retval = CoreTools.start_process(cmd, show_output=False, privileged=True) #Get the package cache if there is none. 200 - locking failure. if package_manager == "dnf" and retval not in (0, 200): CoreTools.start_process("sh -c 'echo No cache available, " + "downloading package information...'") if mount_point != "": cmd2 = "chroot "+mount_point+" dnf check-update" else: cmd2 = "dnf check-update" CoreTools.start_process(cmd2, show_output=False, privileged=True) time.sleep(5)
def backup_uefi_files(mount_point): """Backup some .efi files, just in case something goes wrong.""" #TODO: Make this smarter when we detect Windows. logger.info("backup_uefi_files(): Backing up UEFI Files...") #We'll backup /EFI/boot/bootx64.efi if it exists, and we'll also backup Windows's uefi files, #if they exist. First do /EFI/boot/bootx64.efi. Fortunately, the UEFI partition is always a #fat32/fat16 filesystem, so case doesn't matter. logger.info("backup_uefi_files(): Backing up "+mount_point+"/boot/efi/boot/boot*.efi...") if os.path.isfile(mount_point+"/boot/efi/EFI/boot/boot*.efi"): if CoreTools.start_process("cp -v "+mount_point+"/boot/efi/EFI/boot/boot*.efi " + mount_point+"/boot/efi/EFI/boot/bkpbootx64.efi", show_output=False, privileged=True) != 0: #Log and warn user if this went wrong. logger.error("backup_uefi_files(): Failed to backup failsafe UEFI boot file! " + "Warning user and continuing...") DialogTools.show_msg_dlg(kind="warning", message="WxFixBoot failed to save " + "your UEFI boot files to the backup directory! Click okay to continue.") #Now do Windows's files, if they exist. logger.info("backup_uefi_files(): Backing up Windows's boot files if they exist...") if os.path.isfile(mount_point+"/boot/efi/EFI/Microsoft/boot/bootmgfw.efi"): if CoreTools.start_process("cp -v "+mount_point+"/boot/efi/EFI/Microsoft/boot/bootmgfw.efi " + mount_point+"/boot/efi/EFI/Microsoft/boot/bkpbootmgfw.efi", show_output=False, privileged=True) != 0: #Log and warn user if this went wrong. logger.error("backup_uefi_files(): Failed to backup Windows's UEFI boot files! " + "Warning user and continuing...") DialogTools.show_msg_dlg(kind="warning", message="WxFixBoot failed to " + "backup Windows's UEFI boot files! Click okay to continue.") logger.info("backup_uefi_files(): Done!")
def mount_core_filesystems(): """ Mount all core filsystems defined in the /etc/fstab of the current operating system. """ logger.info("mount_core_filesystems(): Mounting core filesystems in /etc/fstab. Calling " + "'mount -avw'...") #Don't worry about this error when running on Parted Magic. if CoreTools.start_process("mount -avw", privileged=True) != 0 \ and SYSTEM_INFO["OnPartedMagic"] is False: logger.critical("mount_core_filesystems(): Failed to re-mount your filesystems after " + "checking them! Doing emergency exit...") CoreTools.emergency_exit("Failed to re-mount your filesystems after checking them!")
def install_grub2_to_mbr(package_manager, use_chroot, mount_point, device): """Install GRUB2 (BIOS version) into the MBR of the hard drive""" #Okay, we've modified the kernel options and the timeout. Now we need to install grub to find #the MBR. Use --force to make sure grub installs it even on a GPT disk with no bios boot #partition. Can flag as a warning on Fedora systems when just updating, but ignore it. if package_manager == "apt-get": cmd = "grub-install --force "+device elif package_manager == "dnf": cmd = "grub2-install --force --target=i386-pc "+device if use_chroot: cmd = "chroot "+mount_point+" "+cmd retval = CoreTools.start_process(cmd, show_output=False, privileged=True) #Return the return value. return retval
def determine_os_architecture(mount_point): """Look for OS architecture on given partition.""" if mount_point != "": logger.info("determine_os_architecture(): Trying to find OS arch for OS at " + mount_point+"...") else: logger.info("determine_os_architecture(): Trying to find OS arch for Current OS...") #Do setup. os_architecture = None cmd = "arch" while True: if mount_point != "": cmd = "chroot "+mount_point+" "+cmd retval, os_architecture = CoreTools.start_process(cmd, return_output=True, privileged=True) #If the command failed, try a second approach. if retval != 0 and "arch" in cmd: cmd = "file /sbin/init" elif retval != 0: os_architecture = None break else: break #If the command that worked was 'arch', or both failed, we can just return it. if "arch" in cmd or retval != 0: #Return the arch (or None, if we didn't find it). return os_architecture else: if "32-bit" in os_architecture: os_architecture = "i386" else: os_architecture = "x86_64" return os_architecture
def get_os_name_with_lsb(partition, mount_point, is_current_os): """Attempt to get an OS's name using lsb_release -sd as a fallback.""" logger.info("get_os_name_with_lsb(): Attempting to get OS name for OS on "+partition+"...") if is_current_os: logger.info("get_os_name_with_lsb(): OS is the currently running OS...") cmd = "lsb_release -sd" else: logger.info("get_os_name_with_lsb(): OS isn't the currently running OS...") cmd = "chroot "+mount_point+" lsb_release -sd" retval, output = CoreTools.start_process(cmd, show_output=False, return_output=True, privileged=True) if retval != 0 or output == "": logger.error("get_os_name_with_lsb(): Couldn't get OS name! Returning None...") return None #otherwise... logger.info("get_os_name_with_lsb(): Success. OS name is "+output+". Returning it...") return output
def update_grub2(_os, package_manager, use_chroot, mount_point): """ Run 'update-grub' to update GRUB2's (BIOS and EFI/UEFI) configuration and bootloader menu """ #We need to update grub. if package_manager == "apt-get": cmd = "update-grub2" elif package_manager == "dnf" and BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB2": cmd = "grub2-mkconfig -o /boot/grub2/grub.cfg" elif package_manager == "dnf": cmd = "grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg" if use_chroot: cmd = "chroot "+mount_point+" "+cmd retval = CoreTools.start_process(cmd, show_output=False, privileged=True) #Return the return value. return retval
def install_grub2_to_efi_partition(package_manager, use_chroot, mount_point, uefi_system_partition_mount_point, arch): """Install GRUB2 (EFI/UEFI version) into the EFI/UEFI partition""" #Okay, we've modified the kernel options and the timeout. Now we need to install grub #to the UEFI partition. #NB: May need --force if EFI vars not present on newer GRUB-EFI versions (Ubuntu 18.10+) check! #NB: Don't think so - files touched anyway, but good to double check. #NB: Keep an eye on this. if package_manager == "apt-get": cmd = "grub-install --efi-directory="+uefi_system_partition_mount_point \ + " --target="+arch+"-efi" elif package_manager == "dnf": #Don't install on fedora, it messes stuff up. cmd = "echo 'Disabled on Fedora'" if use_chroot: cmd = "chroot "+mount_point+" "+cmd retval = CoreTools.start_process(cmd, show_output=False, privileged=True) #Return the return value. return retval
def determine_package_manager(apt_cmd, dnf_cmd): """ Determine and return the package manager using the given command strings. """ package_manager = "Unknown" for cmd in (apt_cmd, dnf_cmd): retval = CoreTools.start_process(cmd, show_output=False, privileged=True) if retval != 0: if cmd == apt_cmd: #Couldn't find apt! logger.info("MainStartupTools: Main().determine_package_manager(): Didn't find " + "apt. Looking for dnf...") continue else: logger.info("MainStartupTools: Main().determine_package_manager(): Didn't find " + "apt or dnf. Returning 'Unknown'...") else: if cmd == apt_cmd: #Found APT! logger.info("MainStartupTools: Main().determine_package_manager(): Found apt...") package_manager = "apt-get" break else: #Found DNF! logger.info("MainStartupTools: Main().determine_package_manager(): Found dnf...") package_manager = "dnf" break return package_manager
def check_internet_connection(): """Check the internet connection.""" logger.info( "check_internet_connection(): Checking the Internet Connection w/ OpenDNS..." ) while True: #Test the internet connection by pinging an OpenDNS DNS server. packet_loss = "100%" logger.debug( "check_internet_connection(): Running 'ping -c 5 -i 0.5 208.67.222.222'..." ) retval, output = CoreTools.start_process( "ping -c 5 -i 0.5 208.67.222.222", show_output=False, return_output=True) if retval != 0: #This errored for some reason. Probably no internet connection. logger.error("check_internet_connection(): Command errored!") packet_loss = "100%" else: #Get the % packet loss. for line in output.split("\n"): if 'packet loss' in line: packet_loss = line.split()[-5] if packet_loss == "0%": #Good! We have a reliable internet connection. logger.info( "check_internet_connection(): Internet Connection Test Succeeded!" ) break else: #Uh oh! We DON'T have a reliable internet connection! Ask the user to either try again, #or skip Bootloader operations. logger.error( "check_internet_connection(): Internet Connection test failed! Asking " + "user to try again or disable bootloader operations...") result = DialogTools.show_yes_no_dlg( message="Your Internet Connection failed the " + "test! Without a working internet connection, " + "you cannot perform bootloader operations. " + "Click yes to try again, and click no to give " + "up and skip bootloader operations.", title="WxFixBoot - Disable Bootloader " + "Operations?", buttons=("Try again", "Cancel Bootloader Operations")) if result is False: logger.warning( "check_internet_connection(): Disabling bootloader operations " + "due to bad internet connection...") SYSTEM_INFO["DisableBootloaderOperations"] = True SYSTEM_INFO["DisableBootloaderOperationsBecause"] \ .append("Internet Connection test failed.") break else: #We'll just run the loop again logger.info( "check_internet_connection(): Testing the internet connection " + "again...")
def remove_old_bootloader(_os): """Remove the currently installed bootloader.""" logger.info("remove_old_bootloader(): Removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 27) wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "......") wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "...###\n") #If this is the current OS, let the remover function know that we aren't using chroot. if OS_INFO[_os]["IsCurrentOS"]: logger.debug( "remove_old_bootloader(): Modifying current OS so not using chroot..." ) use_chroot, unmount_after, mount_point = (False, False, "") else: logger.debug( "remove_old_bootloader(): Using chroot to modify another OS...") use_chroot = True mount_point = "/mnt/wxfixboot/mountpoints" + OS_INFO[_os]["Partition"] #Check if the partition is mounted. unmount_after = not CoreTools.is_mounted(OS_INFO[_os]["Partition"], mount_point) if unmount_after: #Mount the partition using the global mount function. if CoreTools.mount_partition(partition=OS_INFO[_os]["Partition"], mount_point=mount_point) != 0: logger.error("remove_old_bootloader(): Failed to mount " + OS_INFO[_os]["Partition"] + "! Warning the user and giving up...") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount the partition " + "containing " + _os + "! Giving up. You will be prompted " + "to try again if you wish.") return False #Set up chroot. if CoreTools.setup_chroot(mount_point) != 0: logger.error( "remove_old_bootloader(): Failed to set up chroot at " + mount_point + "! Giving up...") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to set up a chroot for " + _os + "! Giving up. You will be prompted to try again if " + "you wish.") return False #Mount a /boot partition if it exists. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.mount_partition(OS_INFO[_os]["BootPartition"], mount_point + "/boot") != 0: logger.error("remove_old_bootloader(): Failed to mount " + _os + "'s /boot partition! " + "Skipping bootloader removal for this OS.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount the partition containing " + _os + "'s /boot partition! Giving up. You will be prompted " + "to try again if you wish.") if not OS_INFO[_os]["IsCurrentOS"]: CoreTools.teardown_chroot(mount_point) CoreTools.unmount(mount_point) return False #Mount the UEFI partition at mount_point/boot/efi, if it exists. if OS_INFO[_os]["EFIPartition"] != "Unknown": if CoreTools.mount_partition( partition=OS_INFO[_os]["EFIPartition"], mount_point=mount_point + "/boot/efi") != 0: logger.error("remove_old_bootloader(): Failed to mount " + OS_INFO[_os]["EFIPartition"] + "! to " + mount_point + "/boot/efi! Aborting bootloader installation and " + "warning user...") DialogTools.show_msg_dlg( kind="error", message="WxfixBoot failed to mount the partition containing " + _os + "'s EFI partition! Giving up. You will be prompted to " + "try again if you wish.") return False #Wait until no other application is using APT/DNF. #Let user know what's happening. wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 27) wx.CallAfter( wx.GetApp().TopWindow.update_current_operation_text, message="Waiting until " + _os + "'s package manager is free.\nClose any open applications if this " + "message persists...") wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Waiting until " + _os + "'s package manager is free...###\n") logger.debug("remove_old_bootloader(): Waiting until " + _os + "'s package manager is free...") HelperBackendTools.wait_until_packagemanager_free(mount_point=mount_point, package_manager=\ OS_INFO[_os]["PackageManager"]) wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 27) wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "...") wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "...###\n") #Make sure the GNOME APT frontend dependency is installed. if OS_INFO[_os]["PackageManager"] == "apt-get": #Ubuntu 16.04. cmd = "sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y libgnome2-perl'" if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) #All newer versions. cmd = "sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y libgtk3-perl'" if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) #Remove the bootloader. if BOOTLOADER_INFO[_os]["Bootloader"] == "GRUB2": logger.info("remove_old_bootloader(): Removing GRUB2...") if OS_INFO[_os]["PackageManager"] == "apt-get": cmd = "sh -c 'DEBIAN_FRONTEND=gnome DISPLAY=:0 apt-get purge -y " \ "--allow-remove-essential grub-pc grub-pc-bin grub-common'" elif OS_INFO[_os]["PackageManager"] == "dnf": cmd = "dnf -y remove grub2" elif BOOTLOADER_INFO[_os]["Bootloader"] == "GRUB-UEFI": logger.info("remove_old_bootloader(): Removing GRUB-UEFI...") if OS_INFO[_os]["PackageManager"] == "apt-get": cmd = "sh -c 'DEBIAN_FRONTEND=gnome DISPLAY=:0 apt-get purge -y " \ "--allow-remove-essential grub-efi grub-efi-amd64 grub-efi-amd64-bin" \ " grub-efi-ia32 grub-efi-ia32-bin grub-common grub2-common'" elif OS_INFO[_os]["PackageManager"] == "dnf": cmd = "dnf -y remove grub2-efi-x64 grub2-efi-ia32 shim-x64" else: #Bootloader is unknown. Just output a warning message. logger.warning( "remove_old_bootloader(): Cannot remove unknown bootloader! " + "Continuing anyway...") cmd = "echo 'WARNING: Bootloader is " \ "unknown, cannot remove. Continuing anyway...'" if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) if retval != 0: logger.error("remove_old_bootloader(): Failed to remove " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "! Warning user...") DialogTools.show_msg_dlg(kind="error", message="WxFixBoot failed to remove " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "!") return False #If there's a seperate EFI partition for this OS, make sure it's unmounted before removing #the chroot. if OS_INFO[_os]["EFIPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot/efi") != 0: logger.error("remove_old_bootloader(): Failed to unmount " + mount_point + "/boot/efi! This probably doesn't matter...") #unmount a /boot partition if it exists. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot") != 0: logger.error("remove_old_bootloader(): Failed to unmount " + _os + "'s /boot partition! Continuing anyway...") #Tear down chroot if needed. if use_chroot: if CoreTools.teardown_chroot(mount_point=mount_point) != 0: logger.error( "remove_old_bootloader(): Failed to remove chroot at " + mount_point + "! Attempting to continue anyway...") #unmount partition if needed. if unmount_after: if CoreTools.unmount(mount_point) != 0: logger.error("remove_old_bootloader(): Couldn't unmount " + mount_point + "! Continuing anyway...") wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Finished removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "...###\n") if retval != 0: #Something went wrong! Log it and notify the user. logger.error("remove_old_bootloader(): Failed to remove " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "! We'll continue anyway. Warn the user.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to remove " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "! This probably doesn't matter; when we install the new " + "bootloader, it should take precedence over the old one " + "anyway. Make sure you check that " + _os + " boots correctly " + "after WxFixBoot finishes its operations. Reinstalling the " + "bootloader again afterwards is recommended.") #Attempt to clear any stuck logical volumes that may have been created by os-prober. CoreTools.start_process("dmsetup remove_all -y", privileged=True) #Make sure any LVM volume groups are active. for disk in DISK_INFO: if "VGName" in DISK_INFO[disk]: CoreTools.start_process("vgchange -a y " + DISK_INFO[disk]["VGName"], privileged=True) #Log and notify the user that we're finished removing bootloaders. logger.info("remove_old_bootloader(): Finished removing " + BOOTLOADER_INFO[_os]["Bootloader"] + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Finished removing " + BOOTLOADER_INFO[_os]["Bootloader"] + " from " + _os + "......") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 50) return True
def get_oss(): """Get the names of all OSs on the HDDs.""" logger.info("get_oss(): Finding operating systems...") root_filesystem = CoreTools.get_partition_mounted_at("/") os_info = {} #Get Linux OSs. keys = list(DISK_INFO.keys()) keys.sort() for partition in keys: if DISK_INFO[partition]["Type"] == "Device": continue elif DISK_INFO[partition]["FileSystem"] in ("hfsplus", "hfs", "apfs"): #TODO Check if this is what APFS shows up as. #Look for macOS. os_name = "macOS ("+partition+")" logger.debug("get_oss(): Looking for macOS on "+partition+"...") #Check if we need to mount the partition. was_mounted = False if CoreTools.is_mounted(partition): #If mounted, get the mountpoint. mount_point = CoreTools.get_mount_point_of(partition) else: #Mount the partition and check if anything went wrong. mount_point = "/mnt/wxfixboot/mountpoints"+partition if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. logger.warning("get_oss(): Couldn't mount "+partition + "! Skipping this partition...") continue was_mounted = True if os.path.exists(mount_point+"/mach_kernel") \ or os.path.exists(mount_point+"/System/Library/Kernels/kernel"): #Create OS_INFO entry for it. logger.debug("get_oss(): Found "+os_name+"...") os_info[os_name] = {} os_info[os_name]["Name"] = os_name os_info[os_name]["IsCurrentOS"] = False os_info[os_name]["Arch"] = "Unknown" os_info[os_name]["Partition"] = partition os_info[os_name]["PackageManager"] = "Mac App Store" os_info[os_name]["RawFSTabInfo"], os_info[os_name]["EFIPartition"], \ os_info[os_name]["BootPartition"] = (["Unknown"], "Unknown", "Unknown") #unmount the filesystem if needed. if was_mounted: if CoreTools.unmount(mount_point) != 0: logger.error("get_oss(): Couldn't unmount "+partition + "! Doing emergency exit...") CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for " + "operating systems on it! Please reboot your " + "computer and try again.") elif DISK_INFO[partition]["FileSystem"] in ("vfat", "ntfs", "exfat"): #Look for Windows. NOTE: It seems NTFS volumes can't be mounted twice, which is why #we're being more careful here. #TODO ^ Check, I think it worked before. Good to be cautious either way. logger.debug("get_oss(): Looking for Windows on "+partition+"...") #Check if we need to mount the partition. was_mounted = False if CoreTools.is_mounted(partition): #If mounted, get the mountpoint. mount_point = CoreTools.get_mount_point_of(partition) else: #Mount the partition and check if anything went wrong. mount_point = "/mnt/wxfixboot/mountpoints"+partition if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. logger.warning("get_oss(): Couldn't mount "+partition + "! Skipping this partition...") continue was_mounted = True #Check if there's a Windows/WinNT dir. if not (os.path.isdir(mount_point+"/WinNT") or os.path.isdir(mount_point+"/Windows") \ or os.path.isdir(mount_point+"/WINDOWS")): #Skip this partition, and unmount if needed. logger.info("get_oss(): Windows wasn't found...") else: #Look for lots of different Windows editions. #Look for the newest ones first, due to references to old versions #in the licenses messing up our version detection. if CoreStartupTools.has_windows_10(mount_point): os_name = "Windows 10" elif CoreStartupTools.has_windows_8(mount_point): os_name = "Windows 8/8.1" elif CoreStartupTools.has_windows_7(mount_point): os_name = "Windows 7" elif CoreStartupTools.has_windows_vista(mount_point): os_name = "Windows Vista" elif CoreStartupTools.has_windows_xp(mount_point): os_name = "Windows XP" elif CoreStartupTools.has_windows_9x(mount_point): os_name = "Windows 95/98/ME" else: #Unknown Windows. os_name = "Windows" #Create os_info entry for it. os_name = os_name+" ("+partition+")" logger.debug("get_oss(): Found "+os_name+"...") os_info[os_name] = {} os_info[os_name]["Name"] = os_name os_info[os_name]["IsCurrentOS"] = False os_info[os_name]["Arch"] = "Unknown" os_info[os_name]["Partition"] = partition os_info[os_name]["PackageManager"] = "Windows Installer" os_info[os_name]["RawFSTabInfo"], os_info[os_name]["EFIPartition"], \ os_info[os_name]["BootPartition"] = (["Unknown"], "Unknown", "Unknown") #unmount the filesystem if needed. if was_mounted: if CoreTools.unmount(mount_point) != 0: logger.error("get_oss(): Couldn't unmount "+partition +"! Doing emergency exit...") CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for " + "operating systems on it! Please reboot your " + "computer and try again.") else: #Look for Linux. #The python command runs on python 3. logger.debug("get_oss(): Looking for Linux on "+partition+"...") #If there are aliases for partition, check if the root FS is one of those too. root_filesystem_is_alias = False if "Aliases" in DISK_INFO[partition]: logger.debug("get_oss(): Checking if RootFS is an alias for "+partition+"...") if root_filesystem in DISK_INFO[partition]["Aliases"]: logger.debug("get_oss(): RootFS is an alias...") root_filesystem_is_alias = True else: logger.debug("get_oss(): RootFS isn't an alias...") root_filesystem_is_alias = False if partition == root_filesystem or root_filesystem_is_alias: cmd = "cat /etc/os-release" apt_cmd = "which apt-get" dnf_cmd = "which dnf" chroot = False is_current_os = True mount_point = "" else: mount_point = "/mnt/wxfixboot/mountpoints"+partition cmd = "cat "+mount_point+"/etc/os-release" apt_cmd = "chroot "+mount_point+" which apt-get" dnf_cmd = "chroot "+mount_point+" which dnf" chroot = True is_current_os = False #Mount the partition and check if anything went wrong. if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. logger.warning("get_oss(): Couldn't mount "+partition + "! Skipping this partition...") continue #Look for Linux on this partition. retval, temp = CoreTools.start_process(cmd, return_output=True) os_name = "" try: for line in temp.split("\n"): if "PRETTY_NAME" in line: os_name = line.split("=")[1].replace('\"', '') except IndexError: os_name = "" #Run the function to get the architechure. os_architecture = CoreStartupTools.determine_os_architecture(mount_point=mount_point) #If the OS's name wasn't found, but its architecture was, there must be an OS here, so #try to use lsb_release if possible before asking the user. Catch if the name is just #whitespace too. if (retval != 0 or os_name == "" or os_name.isspace()) and os_architecture != None: os_name = CoreStartupTools.get_os_name_with_lsb(partition=partition, mount_point=mount_point, is_current_os=is_current_os) #If we really have to, ask the user. if os_name is None: logger.warning("get_oss(): Asking user for OS name instead...") os_name = CoreStartupTools.ask_for_os_name(partition=partition, is_current_os=is_current_os) #Look for APT. package_manager = CoreStartupTools.determine_package_manager(apt_cmd=apt_cmd, dnf_cmd=dnf_cmd) #Also check if CoreStartupTools.ask_for_os_name was used to determine the name. #If the user skipped naming the OS, ignore it and skip the rest of this loop iteration. if os_name is not None and os_architecture is not None and package_manager != "Unknown": #Add this information to os_info. os_info[os_name] = {} os_info[os_name]["Name"] = os_name os_info[os_name]["IsCurrentOS"] = is_current_os os_info[os_name]["Arch"] = os_architecture os_info[os_name]["Partition"] = partition os_info[os_name]["PackageManager"] = package_manager os_info[os_name]["RawFSTabInfo"], os_info[os_name]["EFIPartition"], \ os_info[os_name]["BootPartition"] = \ CoreStartupTools.get_fstab_info(mount_point, os_name) if chroot is False: SYSTEM_INFO["CurrentOS"] = os_info[os_name].copy() if chroot: #unmount the filesystem. if CoreTools.unmount(mount_point) != 0: logger.error("get_oss(): Couldn't unmount "+partition + "! Doing emergency exit...") CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for " + "operating systems on it! Please reboot your " + "computer and try again.") #Check that at least one Linux OS was detected. linux_oss = [] #Get list of Linux OSs. for _os in os_info: if _os[0] not in ("Windows", "macOS"): linux_oss.append(os_name) if not linux_oss: logger.critical("get_oss(): No Linux installations found! If you do have Linux " + "installations but WxFixBoot hasn't found them, please file a bug or " + "ask a question on WxFixBoot's launchpad page. If you're using Windows " + "or macOS, then sorry as WxFixBoot has no support for these operating " + "systems. You could instead use the tools provided by Microsoft and " + "Apple to fix any issues with your computer. Exiting...") #Exit. CoreTools.emergency_exit("You don't appear to have any Linux installations on your hard " + "disks. If you do have Linux installations but WxFixBoot " + "hasn't found them, please file a bug or ask a question on " + "WxFixBoot's launchpad page. If you're using Windows or macOS, " + "then sorry as WxFixBoot has no support for these operating " + "systems. You could instead use the tools provided by Microsoft " + "and Apple to fix any issues with your computer.") #Otherwise... logger.debug("get_oss(): Done, os_info Populated okay. Contents: "+str(os_info)) return os_info, SYSTEM_INFO
def install_new_bootloader(_os): """Install a new bootloader.""" logger.info("install_new_bootloader(): Preparing to install " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 52) wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Preparing to install " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...###\n") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Preparing to install " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...") #If this is the current OS, let the installer functions know that we aren't using chroot. if OS_INFO[_os]["IsCurrentOS"]: logger.debug( "install_new_bootloader(): Modifying current OS so not using chroot..." ) use_chroot, unmount_after, mount_point = (False, False, "") #Otherwise, setup the chroot and everything else first, and tell them we are using chroot, #and pass the mountpoint to them. else: logger.debug( "install_new_bootloader(): Using chroot to modify another OS...") use_chroot = True mount_point = "/mnt/wxfixboot/mountpoints" + OS_INFO[_os]["Partition"] #Check if the partition is mounted. unmount_after = not CoreTools.is_mounted(OS_INFO[_os]["Partition"], mount_point) if unmount_after: if CoreTools.mount_partition(partition=OS_INFO[_os]["Partition"], mount_point=mount_point) != 0: logger.error("install_new_bootloader(): Failed to mount " + OS_INFO[_os]["Partition"] + "! Warn the user and skip this OS.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount the partition " + "containing " + _os + "! Bootloader installation cannot " + "continue! This may leave your system, or this OS, in " + "an unbootable state. Please close any open programs, " + "then try again when prompted.") return False #Set up chroot. if CoreTools.setup_chroot(mount_point=mount_point) != 0: logger.error( "install_new_bootloader(): Failed to set up chroot at " + mount_point + "! Warning user and giving up...") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to set up a chroot for " + _os + "! Giving up. You will be prompted to try again if " + "you wish.") return False #If there's a seperate /boot partition for this OS, make sure it's mounted. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.mount_partition(partition=OS_INFO[_os]["BootPartition"], mount_point=mount_point + "/boot") != 0: logger.error("remove_old_bootloader(): Failed to mount " + OS_INFO[_os]["BootPartition"] + "! Warn the user and skip this OS.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount the partition " + "containing " + _os + "'s /boot partition! Giving up. " + "You will be prompted to try again if you wish.") return False #Update the package lists. if OS_INFO[_os]["PackageManager"] == "apt-get": cmd = "sh -c 'DEBIAN_FRONTEND=gnome DISPLAY=:0 apt-get update'" elif OS_INFO[_os]["PackageManager"] == "dnf": cmd = "dnf check-update" if use_chroot: cmd = "chroot " + mount_point + " " + cmd if CoreTools.start_process(cmd, privileged=True) not in (0, 100): logger.error( "install_new_bootloader(): Failed to Update the Package Information! " + "Continuing anyway...") DialogTools.show_msg_dlg( kind="error", message="WxfixBoot failed to update " + _os + "'s package information! Giving up. You will be prompted " + "to try again if you wish.") return False wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Installing " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 55) wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Installing " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...###\n") #Make sure all GNOME APT frontend dependency is installed. if OS_INFO[_os]["PackageManager"] == "apt-get": #Ubuntu 16.04. cmd = "sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y libgnome2-perl'" if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) #All newer versions. cmd = "sh -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y libgtk3-perl'" if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) #Install the bootloader. if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB2": logger.info("install_new_bootloader(): Installing GRUB2...") if OS_INFO[_os]["PackageManager"] == "apt-get": cmd = "sh -c 'DEBIAN_FRONTEND=gnome DISPLAY=:0 apt-get install -y grub-pc os-prober'" elif OS_INFO[_os]["PackageManager"] == "dnf": cmd = "dnf -y install grub2" elif BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB-UEFI": logger.info("install_new_bootloader(): Installing GRUB-UEFI...") #Mount the UEFI partition at mount_point/boot/efi. if CoreTools.mount_partition( partition=OS_INFO[_os]["EFIPartition"], mount_point=mount_point + "/boot/efi") != 0: logger.error("install_new_bootloader(): Failed to mount " + OS_INFO[_os]["EFIPartition"] + " to " + mount_point + "/boot/efi! Aborting bootloader installation and " + "warning user...") DialogTools.show_msg_dlg( kind="error", message="WxfixBoot failed to mount the partition containing " + _os + "'s EFI partition! Giving up. You will be prompted to " + "try again if you wish.") return False if OS_INFO[_os]["PackageManager"] == "apt-get": cmd = "sh -c 'DEBIAN_FRONTEND=gnome DISPLAY=:0 apt-get install -y grub-efi os-prober'" elif OS_INFO[_os]["PackageManager"] == "dnf": cmd = "dnf -y install grub2-efi-ia32 grub2-efi-x64 shim-x64 " if use_chroot: cmd = "chroot " + mount_point + " " + cmd retval = CoreTools.start_process(cmd, privileged=True) if retval != 0: logger.error( "install_new_bootloader(): Failed to install new bootloader. Warn user..." ) DialogTools.show_msg_dlg(kind="error", message="WxfixBoot failed to install " + _os + "'s new bootloader! Continuing anyway...") #If there's a seperate EFI partition for this OS, make sure it's unmounted before removing #the chroot. if OS_INFO[_os]["EFIPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot/efi") != 0: logger.error("install_new_bootloader(): Failed to unmount " + mount_point + "/boot/efi! This probably doesn't matter...") #If there's a seperate /boot partition for this OS, make sure it's unmounted before #removing the chroot. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot") != 0: logger.error("install_new_bootloader(): Failed to unmount " + mount_point + "/boot! This probably doesn't matter...") if use_chroot: logger.debug("install_new_bootloader(): Removing chroot...") #Tear down chroot. if CoreTools.teardown_chroot(mount_point=mount_point) != 0: logger.error( "install_new_bootloader(): Failed to remove chroot at " + mount_point + "! Attempting to continue anyway...") if unmount_after: if CoreTools.unmount(mount_point) != 0: logger.error("install_new_bootloader(): Failed to unmount " + mount_point + "! Continuing anyway...") if retval != 0: #Something went wrong! Log it and notify the user. logger.error( "install_new_bootloader(): Failed to install " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "! This may mean the system (or this OS) is now unbootable! " + "Warning the user and asking to try again.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to install " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "! This may leave this OS, or your system, in an unbootable " + "state. You will now be prompted to try again.") return False wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Finished installing " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...###\n") #Attempt to clear any stuck logical volumes that may have been created by os-prober. CoreTools.start_process("dmsetup remove_all -y", privileged=True) #Make sure any LVM volume groups are active. for disk in DISK_INFO: if "VGName" in DISK_INFO[disk]: CoreTools.start_process("vgchange -a y " + DISK_INFO[disk]["VGName"], privileged=True) #Log and notify the user that we're finished installing the bootloader. logger.info("install_new_bootloader(): Finished installing " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Finish installing " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " in " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 75) return True
def check_for_live_disk(): """Try to determine if we're running on a live disk.""" logger.info("MainStartupTools(): check_for_live_disk(): Attempting to check if we're on a " + "live disk...") #Detect Parted Magic automatically. if "pmagic" in CoreTools.start_process("uname -r", return_output=True)[1]: logger.info("MainStartupTools(): check_for_live_disk(): Running on Parted Magic...") SYSTEM_INFO["IsLiveDisk"] = True SYSTEM_INFO["OnPartedMagic"] = True #Try to detect ubuntu-based livecds. elif CoreTools.is_mounted("/cow", "/") and os.path.isfile("/cdrom/casper/filesystem.squashfs"): logger.info("MainStartupTools(): check_for_live_disk(): " + "Running on Ubuntu-based live disk...") SYSTEM_INFO["IsLiveDisk"] = True SYSTEM_INFO["OnPartedMagic"] = False #Try to detect fedora-based livecds. elif CoreTools.is_mounted("/dev/mapper/live-rw", "/") \ and os.path.isfile("/run/initramfs/live/LiveOS/squashfs.img"): logger.info("MainStartupTools(): check_for_live_disk(): " + "Running on Fedora-based live disk...") SYSTEM_INFO["IsLiveDisk"] = True SYSTEM_INFO["OnPartedMagic"] = False #Try to detect Disk Verifier/any other live disks. elif CoreTools.is_mounted("overlay", "/") \ or os.path.isfile("/run/live/medium/live/filesystem.squashfs"): logger.info("MainStartupTools(): check_for_live_disk(): " + "Running on live disk...") SYSTEM_INFO["IsLiveDisk"] = True SYSTEM_INFO["OnPartedMagic"] = False #Try to detect if we're not running on a live disk (on HDD/NVME). elif "/dev/sd" in CoreTools.get_partition_mounted_at("/") \ or "/dev/nvme" in CoreTools.get_partition_mounted_at("/"): logger.info("MainStartupTools(): check_for_live_disk(): Not running on live disk...") SYSTEM_INFO["IsLiveDisk"] = False SYSTEM_INFO["OnPartedMagic"] = False #Try to detect if we're not running on a live disk (on LVM). elif "/dev/mapper/" in CoreTools.get_partition_mounted_at("/"): logger.info("MainStartupTools(): check_for_live_disk(): Not running on live disk...") SYSTEM_INFO["IsLiveDisk"] = False SYSTEM_INFO["OnPartedMagic"] = False #Ask the user if we're running on a live disk. else: logger.info("MainStartupTools(): check_for_live_disk(): Asking the user if we're running " + "on live media...") SYSTEM_INFO["IsLiveDisk"] = DialogTools.show_yes_no_dlg(message="Is WxFixBoot being run " + "on live media, such as an " + "Ubuntu Installer Disk?", title="WxFixBoot - Live Media?") SYSTEM_INFO["OnPartedMagic"] = False logger.info("MainStartupTools(): check_for_live_disk(): Result: " + str(SYSTEM_INFO["IsLiveDisk"])) #Get current OS architecture. logger.info("MainStartupTools(): check_for_live_disk(): Getting architecture of current OS...") SYSTEM_INFO["CurrentOSArch"] = CoreStartupTools.determine_os_architecture(mount_point="")
def set_new_bootloader_config(_os): """Manage setting new bootloader config.""" logger.info("set_new_bootloader_config(): Setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "'s config for " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + " config for " + _os + "...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 79) wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "'s config for " + _os + "...###\n") #If this is the current OS, let the config functions know that we aren't using chroot. if OS_INFO[_os]["IsCurrentOS"]: logger.debug( "set_new_bootloader_config(): We're modifying the current OS...") #If so, make sure this will work for this OS too, and avoid setting mountpoint, so the #config instructions below look in the right place for the config files. use_chroot, unmount_after, mount_point = (False, False, "") else: logger.debug( "set_new_bootloader_config(): We're modifying another OS...") use_chroot = True mount_point = "/mnt/wxfixboot/mountpoints" + OS_INFO[_os]["Partition"] #Check if the partition is mounted. unmount_after = not CoreTools.is_mounted(OS_INFO[_os]["Partition"], mount_point) if unmount_after: #Mount the partition. if CoreTools.mount_partition(partition=OS_INFO[_os]["Partition"], mount_point=mount_point) != 0: #Ignore this partition. logger.warning( "set_new_bootloader_config(): Failed to mount " + OS_INFO[_os]["Partition"] + "! Giving up...") return False #Set up chroot. if CoreTools.setup_chroot(mount_point=mount_point) != 0: logger.error( "set_new_bootloader_config(): Failed to set up chroot at " + mount_point + "! Giving up...") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to set up a chroot for " + _os + "! Giving up. You will be prompted to try again if " + "you wish.") return False wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 81) #Mount a /boot partition if it exists. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.mount_partition(OS_INFO[_os]["BootPartition"], mount_point + "/boot") != 0: logger.error( "set_new_bootloader_config(): Failed to mount " + _os + "'s /boot partition! Skipping bootloader config setting for this OS." ) if not OS_INFO[_os]["IsCurrentOS"]: CoreTools.teardown_chroot(mount_point) CoreTools.unmount(mount_point) return False #If there's a seperate EFI partition for this OS, make sure it's mounted. if OS_INFO[_os]["EFIPartition"] != "Unknown": if CoreTools.mount_partition( partition=OS_INFO[_os]["EFIPartition"], mount_point=mount_point + "/boot/efi") != 0: logger.error("remove_old_bootloader(): Failed to mount " + OS_INFO[_os]["EFIPartition"] + "! Warn the user and skip this OS.") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount the partition containing " + _os + "'s EFI partition! Giving up. You will be prompted to " + "try again if you wish.") return False #On GRUB2, get the new menuentries so we can set the default OS. logger.info( "set_new_bootloader_config(): Reading GRUB2's menu entries to set default OS..." ) if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] in ("GRUB2", "GRUB-UEFI"): #Update GRUB. logger.info( "set_new_bootloader_config(): Updating GRUB2 Configuration...") BootloaderConfigSettingTools.update_grub2( _os=_os, package_manager=OS_INFO[_os]["PackageManager"], use_chroot=use_chroot, mount_point=mount_point) BOOTLOADER_INFO[_os]["NewMenuEntries"] = \ BootloaderConfigObtainingTools.parse_grub2_menu_data(menu_data="", mount_point=mount_point)[1] #Look for the configuration file, based on which SetConfig() function we're about to run. if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] in ("GRUB2", "GRUB-UEFI"): #Check mount_point/etc/default/grub exists. if os.path.isfile(mount_point + "/etc/default/grub"): #It does, we'll run the function to set the config now. logger.info( "set_new_bootloader_config(): Setting GRUB2 Configuration...") BootloaderConfigSettingTools.set_grub2_config( _os=_os, filetoopen=mount_point + "/etc/default/grub", bootloader_timeout=BOOTLOADER_INFO[_os]["Settings"] ["NewTimeout"], kernel_options=BOOTLOADER_INFO[_os]["Settings"] ["NewKernelOptions"], package_manager=OS_INFO[_os]["PackageManager"]) if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB-UEFI": #Mount the UEFI partition at mount_point/boot/efi. if CoreTools.mount_partition( partition=OS_INFO[_os]["EFIPartition"], mount_point=mount_point + "/boot/efi") != 0: logger.error( "set_new_bootloader_config(): Couldn't mount EFI partition " + OS_INFO[_os]["EFIPartition"] + " to install bootloader! Giving up " + "and warning user...") DialogTools.show_msg_dlg( kind="error", message="WxFixBoot failed to mount " + _os + "'s EFI partition! You will now be promtped to give " + "up or try again.") return False #Now Install GRUB-UEFI to the UEFI Partition. logger.info( "set_new_bootloader_config(): Installing GRUB-UEFI to " + OS_INFO[_os]["EFIPartition"] + "...") BootloaderConfigSettingTools.install_grub2_to_efi_partition( package_manager=OS_INFO[_os]["PackageManager"], mount_point=mount_point, use_chroot=use_chroot, uefi_system_partition_mount_point="/boot/efi", arch=OS_INFO[_os]["Arch"]) else: #Now Install GRUB2 to the MBR. logger.info("set_new_bootloader_config(): Installing GRUB2 to " + DISK_INFO[OS_INFO[_os]["Partition"]]["HostDevice"] + "...") BootloaderConfigSettingTools.install_grub2_to_mbr( package_manager=OS_INFO[_os]["PackageManager"], use_chroot=use_chroot, mount_point=mount_point, device=DISK_INFO[OS_INFO[_os]["Partition"]]["HostDevice"]) #Update GRUB. logger.info( "set_new_bootloader_config(): Updating GRUB2 Configuration...") BootloaderConfigSettingTools.update_grub2( _os=_os, package_manager=OS_INFO[_os]["PackageManager"], use_chroot=use_chroot, mount_point=mount_point) if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB-UEFI": #Make an entry in fstab for the UEFI Partition, if needed. HelperBackendTools.write_fstab_entry_for_uefi_partition( _os=_os, mount_point=mount_point) #Copy and backup EFI files where needed. HelperBackendTools.backup_uefi_files(mount_point=mount_point) HelperBackendTools.manage_uefi_files(_os=_os, mount_point=mount_point) if BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB-UEFI" \ and OS_INFO[_os]["PackageManager"] == "dnf": #If we're switching to GRUB-UEFI from BIOS it can mess up GRUB2 and change the boot #commands to linux and initrd instead of linuxefi and initrdefi, preventing boot. #Fix this. The next time GRUB is updated from within the OS it will fix itself. logger.info( "set_new_bootloader_config(): Fixing Fedora's GRUB2-UEFI config (when " + "booted with BIOS, it can go wrong)...") logger.info( "set_new_bootloader_config(): Finding and opening GRUB config file..." ) #Find grub.cfg. (Ubuntu). if os.path.isdir(mount_point + "/boot/grub"): grub_dir = mount_point + "/boot/grub" #(Fedora, EFI) elif os.path.isdir(mount_point + "/boot/efi/EFI/fedora"): grub_dir = mount_point + "/boot/efi/EFI/fedora" #Correct the commands if needed. config = CoreTools.read_privileged_file(grub_dir + "/grub.cfg") new_config = [] for line in config: if "linux16" in line and "/vmlinu" in line: new_config.append( line.replace("linux16", "linuxefi") + "\n") elif "linux" in line and "linuxefi" not in line and "/vmlinu" in line: new_config.append(line.replace("linux", "linuxefi") + "\n") elif "initrd16" in line and ("/initrd" in line or "/initramfs" in line): new_config.append( line.replace("initrd16", "initrdefi") + "\n") elif "initrd" in line and "initrdefi" not in line \ and ("/initrd" in line or "/initramfs" in line): new_config.append( line.replace("initrd", "initrdefi") + "\n") else: new_config.append(line + "\n") #Write the fixed config. CoreTools.write_privileged_file(grub_dir + "/grub.cfg", ''.join(new_config)) #unmount the EFI partition. if CoreTools.unmount(OS_INFO[_os]["EFIPartition"]) != 0: logger.error( "set_new_bootloader_config(): Couldn't unmount EFI partition! " + "This probably won't matter, so we'll continue anyway...") logger.info("set_new_bootloader_config(): Done!") elif BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] == "GRUB2" \ and OS_INFO[_os]["PackageManager"] == "dnf": #If we're switching to GRUB2 from UEFI it can mess up GRUB2 and change the boot #commands to linuxefi and initrdefi instead of linux and initrd, preventing boot. #Fix this. The next time GRUB is updated from within the OS it will fix itself. logger.info( "set_new_bootloader_config(): Fixing Fedora's GRUB2-BIOS config (when " + "booted with EFI, it can go wrong)...") logger.info( "set_new_bootloader_config(): Finding and opening GRUB config file..." ) #Find grub.cfg. (Ubuntu). if os.path.isdir(mount_point + "/boot/grub"): grub_dir = mount_point + "/boot/grub" #(Fedora, BIOS) elif os.path.isdir(mount_point + "/boot/grub2"): grub_dir = mount_point + "/boot/grub2" #Correct the commands if needed. config = CoreTools.read_privileged_file(grub_dir + "/grub.cfg") new_config = [] for line in config: new_config.append(line.replace("linuxefi", "linux")\ .replace("initrdefi", "initrd")+"\n") #Write the fixed config. CoreTools.write_privileged_file(grub_dir + "/grub.cfg", ''.join(new_config)) logger.info("set_new_bootloader_config(): Done!") #If there's a seperate EFI partition for this OS, make sure it's unmounted before #removing the chroot. if OS_INFO[_os]["EFIPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot/efi") != 0: logger.error("set_new_bootloader_config(): Failed to unmount " + mount_point + "/boot/efi! This probably doesn't matter...") #unmount a /boot partition if it exists. if OS_INFO[_os]["BootPartition"] != "Unknown": if CoreTools.unmount(mount_point + "/boot") != 0: logger.error("set_new_bootloader_config(): Failed to unmount " + _os + "'s /boot partition! Continuing anyway...") #Tear down chroot if needed. if use_chroot: if CoreTools.teardown_chroot(mount_point=mount_point) != 0: logger.error( "set_new_bootloader_config(): Failed to remove chroot at " + mount_point + "! Attempting to continue anyway...") #unmount the partition if needed. if unmount_after: if CoreTools.unmount(mount_point) != 0: logger.error("set_new_bootloader_config(): Failed to unmount " + mount_point + "! Continuing anyway...") #Attempt to clear any stuck logical volumes that may have been created by os-prober. CoreTools.start_process("dmsetup remove_all -y", privileged=True) #Make sure any LVM volume groups are active. for disk in DISK_INFO: if "VGName" in DISK_INFO[disk]: CoreTools.start_process("vgchange -a y " + DISK_INFO[disk]["VGName"], privileged=True) logger.debug("set_new_bootloader_config(): Finished setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "'s config for " + _os + "...") wx.CallAfter( wx.GetApp().TopWindow.update_output_box, "\n###Finished setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "'s config for " + _os + "...###\n") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Finished setting " + BOOTLOADER_INFO[_os]["Settings"]["NewBootloader"] + "'s config for " + _os + "!") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 100) return True
def write_fstab_entry_for_uefi_partition(_os, mount_point): """ Write an /etc/fstab entry for the UEFI System Partition, if there isn't already one. DISABLED*** """ #FIXME Disabled cos breaks things. #TODO When I try to fix this, use the new config file readers/writers. return True logger.info("write_fstab_entry_for_uefi_partition(): Preparing to write an fstab entry for " + "the UEFI partition ("+OS_INFO[_os]["EFIPartition"]+")...") write_entry = True #Make the directory mount_point/boot/efi if it doesn't already exist. if os.path.isdir(mount_point+"/boot/efi") is False: CoreTools.start_process("mkdir -p "+mount_point+"/boot/efi", show_output=False, privileged=True) #Open the mount_point/etc/fstab file for reading. If we aren't using chroot, this'll just be #/etc/fstab, otherwise, /mnt/wxfixboot/mountpoints/dev/sdxy/etc/fstab. Also, save its contents #in a variable. fstab = open(mount_point+"/etc/fstab", "r") new_file_contents = [] for line in fstab: if OS_INFO[_os]["EFIPartition"] in line \ or "UUID="+DISK_INFO[OS_INFO[_os]["EFIPartition"]]["UUID"] in line: #This fstab already has an entry for the UEFI System Partition! write_entry = False new_file_contents.append(line) #Check if we need to write the entry. if write_entry is False: #We don't! logger.info("write_fstab_entry_for_uefi_partition(): fstab entry already present! " + "Skipping...") fstab.close() else: #We do. If we can use the UUID, then we will, but otherwise we'll use the standard #device name. logger.info("write_fstab_entry_for_uefi_partition(): Writing fstab entry...") new_file_contents.append("\n#fstab entry for UEFI System Partition (" + OS_INFO[_os]["EFIPartition"]+"), written by WxFixBoot.\n") if DISK_INFO[OS_INFO[_os]["EFIPartition"]]["UUID"] != "Unknown": logger.info("write_fstab_entry_for_uefi_partition(): Using UUID to prevent problems " + "down the line...") new_file_contents.append("UUID="+DISK_INFO[OS_INFO[_os]["EFIPartition"]]["UUID"] + " /boot/efi vfat defaults 0 2\n") else: logger.warning("write_fstab_entry_for_uefi_partition(): We have no UUID for the " + "UEFI Partition: "+OS_INFO[_os]["EFIPartition"]+"! This isn't good, " + "and may cause problems down the line. Continuing anyway, using " + "device name instead...") new_file_contents.append(OS_INFO[_os]["EFIPartition"]+" /boot/efi vfat defaults 0 2\n") #Write the finished lines to the file. fstab.close() fstab = open(mount_point+"/etc/fstab", 'w') fstab.write(''.join(new_file_contents)) fstab.close() logger.info("write_fstab_entry_for_uefi_partition(): Done!")
def look_for_bootloaders_on_partition(the_os, package_manager, mount_point, using_chroot): """Look for bootloaders installed in the OS in the given mount point.""" if using_chroot: logger.debug("look_for_bootloaders_on_partition(): Looking for bootloaders in " + mount_point+"...") else: logger.debug("look_for_bootloaders_on_partition(): Looking for bootloaders in / " + "(Current OS)...") bootloader = "Unknown" available_bootloaders = [] #Okay, let's run a command in the chroot that was set up in FindBootloaderRemovalOSs(), #depending on which package manager this OS uses, and which bootloader is currently installed. if package_manager == "apt-get": cmd = "dpkg --get-selections" else: cmd = "dnf -C list installed" if using_chroot: cmd = "chroot "+mount_point+" "+cmd output = CoreTools.start_process(cmd, show_output=False, return_output=True, privileged=True)[1].split("\n") #Look for them in a specific order to be as fast a possible and to avoid false positives. if package_manager == "apt-get": bootloader_packages = ("grub-efi", "grub-pc") package_dictionary = {"grub-efi": "GRUB-UEFI", "grub-pc": "GRUB2"} else: bootloader_packages = ("grub2-efi-x64", "grub2-pc") package_dictionary = {"grub2-efi-x64": "GRUB-UEFI", "grub2-pc": "GRUB2"} for package in bootloader_packages: found = False for line in output: if package in line: if package_manager == "apt-get": if line.split()[1] != "install": continue found = True break if found: #On Fedora, GRUB2 for BIOS and GRUB2 for UEFI are both installed by default! #To figure out which way we're booting (and which is being used), see whether #we are booting in EFI mode or not. if package_dictionary[package] == "GRUB-UEFI" \ and OS_INFO[the_os]["PackageManager"] == "dnf" \ and SYSTEM_INFO["FirmwareType"] == "BIOS": #We're booting with GRUB2. continue bootloader = package_dictionary[package] logger.info("look_for_bootloaders_on_partition(): Found "+bootloader+"...") break #Look for any other bootloaders that might be available for installation. for package in bootloader_packages: if package_manager == "apt-get": cmd = "apt-cache search "+package else: cmd = "dnf -C search "+package if using_chroot: cmd = "chroot "+mount_point+" "+cmd output = CoreTools.start_process(cmd, show_output=False, return_output=True, privileged=True)[1].split("\n") #Only look in the package name. for line in output: try: if package_manager == "apt-get": correct_section = line.split()[0] else: correct_section = line.split()[0].split(".")[0] except IndexError: continue if package == correct_section: if package_dictionary[package] not in available_bootloaders: available_bootloaders.append(package_dictionary[package]) #Log info. available_bootloaders.sort() logger.info("look_for_bootloaders_on_partition(): Found available bootloaders: " + ', '.join(available_bootloaders)) #Return info. return bootloader, available_bootloaders
def get_oss(): """Get the names of all OSs on the HDDs.""" root_fs = CoreTools.get_partition_mounted_at("/") #Get Linux OSs. keys = list(DISK_INFO.keys()) keys.sort() for partition in keys: if DISK_INFO[partition]["Type"] == "Device": continue elif DISK_INFO[partition]["FileSystem"] in ("hfsplus", "hfs", "apfs"): #Look for Mac OS X. os_name = "Mac OS X ("+partition+")" #Check if we need to mount the partition. was_mounted = False if CoreTools.is_mounted(partition): #If mounted, get the mountpoint. mount_point = CoreTools.get_mount_point_of(partition) else: #Mount the partition and check if anything went wrong. mount_point = "/mnt/wxfixboot/mountpoints"+partition if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. continue was_mounted = True if os.path.exists(mount_point+"/mach_kernel") or os.path.exists(mount_point+"/System/Library/Kernels/kernel"): #Create OS_INFO entry for it. OS_INFO[os_name] = {} OS_INFO[os_name]["Name"] = os_name OS_INFO[os_name]["IsCurrentOS"] = False OS_INFO[os_name]["Arch"] = "Unknown" OS_INFO[os_name]["Partition"] = partition OS_INFO[os_name]["PackageManager"] = "Mac App Store" OS_INFO[os_name]["RawFSTabInfo"], OS_INFO[os_name]["EFIPartition"], OS_INFO[os_name]["BootPartition"] = (["Unknown"], "Unknown", "Unknown") #Unmount the filesystem if needed. if was_mounted: if CoreTools.unmount(mount_point) != 0: break #CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for" # + "operating systems on it! Please reboot your " # + "computer and try again.") elif DISK_INFO[partition]["FileSystem"] in ("vfat", "ntfs", "exfat"): #Look for Windows. NOTE: It seems NTFS volumes can't be mounted twice, which is why #we're being more careful here. #Check if we need to mount the partition. was_mounted = False if CoreTools.is_mounted(partition): #If mounted, get the mountpoint. mount_point = CoreTools.get_mount_point_of(partition) else: #Mount the partition and check if anything went wrong. mount_point = "/mnt/wxfixboot/mountpoints"+partition if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. continue was_mounted = True #Check if there's a Windows/WinNT dir. if not (os.path.isdir(mount_point+"/WinNT") or os.path.isdir(mount_point+"/Windows") or os.path.isdir(mount_point+"/WINDOWS")): #Skip this partition, and unmount if needed. pass else: #Look for lots of different Windows editions. if CoreStartupTools.has_windows_9x(mount_point): os_name = "Windows 95/98/ME" elif CoreStartupTools.has_windows_xp(mount_point): os_name = "Windows XP" elif CoreStartupTools.has_windows_vista(mount_point): os_name = "Windows Vista" elif CoreStartupTools.has_windows_7(mount_point): os_name = "Windows 7" elif CoreStartupTools.has_windows_8(mount_point): os_name = "Windows 8/8.1" elif CoreStartupTools.has_windows_10(mount_point): os_name = "Windows 10" else: #Unknown Windows. os_name = "Windows" #Create OS_INFO entry for it. os_name = os_name+" ("+partition+")" OS_INFO[os_name] = {} OS_INFO[os_name]["Name"] = os_name OS_INFO[os_name]["IsCurrentOS"] = False OS_INFO[os_name]["Arch"] = "Unknown" OS_INFO[os_name]["Partition"] = partition OS_INFO[os_name]["PackageManager"] = "Windows Installer" OS_INFO[os_name]["RawFSTabInfo"], OS_INFO[os_name]["EFIPartition"], OS_INFO[os_name]["BootPartition"] = (["Unknown"], "Unknown", "Unknown") #Unmount the filesystem if needed. if was_mounted: if CoreTools.unmount(mount_point) != 0: break #CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for" # + "operating systems on it! Please reboot your " # + "computer and try again.") else: #Look for Linux. #The python command runs on python 2 and python 3. #If there are aliases for partition, check if the root FS is one of those too. root_fs_is_alias = False if "Aliases" in DISK_INFO[partition]: root_fs_is_alias = (root_fs in DISK_INFO[partition]["Aliases"]) if partition == root_fs or root_fs_is_alias: cmd = "python -c \"from __future__ import print_function; import platform; print(' '.join(platform.linux_distribution()));\"" apt_cmd = "which apt-get" dnf_cmd = "which dnf" chroot = False is_current_os = True mount_point = "" else: mount_point = "/mnt/wxfixboot/mountpoints"+partition cmd = "chroot "+mount_point+" python -c \"from __future__ import print_function; import platform; print(' '.join(platform.linux_distribution()));\"" apt_cmd = "chroot "+mount_point+" which apt-get" dnf_cmd = "chroot "+mount_point+" which dnf" chroot = True is_current_os = False #Mount the partition and check if anything went wrong. if CoreTools.mount_partition(partition=partition, mount_point=mount_point) != 0: #Ignore the partition. continue #Look for Linux on this partition. retval, temp = CoreTools.start_process(cmd, return_output=True) os_name = temp.replace('\n', '') #Run the function to get the architechure. os_arch = CoreStartupTools.determine_os_architecture(mount_point=mount_point) #If the OS's name wasn't found, but its architecture was, there must be an OS here, #so try to use lsb_release if possible before asking the user. Catch if the name is #just whitespace too. if (retval != 0 or os_name == "" or os_name.isspace()) and os_arch != None: os_name = CoreStartupTools.get_os_name_with_lsb(partition=partition, mount_point=mount_point, is_current_os=is_current_os) #If we really have to, ask the user. if os_name is None: os_name = CoreStartupTools.ask_for_os_name(partition=partition, is_current_os=is_current_os) #Look for APT. package_manager = CoreStartupTools.determine_package_manager(apt_cmd=apt_cmd, dnf_cmd=dnf_cmd) #Also check if CoreStartupTools.ask_for_os_name was used to determine the name. #If the user skipped naming the OS, ignore it and skip the rest of this loop iteration. if os_name != None and os_arch != None and package_manager != "Unknown": #Add this information to OS_INFO. OS_INFO[os_name] = {} OS_INFO[os_name]["Name"] = os_name OS_INFO[os_name]["IsCurrentOS"] = is_current_os OS_INFO[os_name]["Arch"] = os_arch OS_INFO[os_name]["Partition"] = partition OS_INFO[os_name]["PackageManager"] = package_manager OS_INFO[os_name]["RawFSTabInfo"], OS_INFO[os_name]["EFIPartition"], OS_INFO[os_name]["BootPartition"] = CoreStartupTools.get_fstab_info(mount_point, os_name) if chroot is False: SYSTEM_INFO["CurrentOS"] = OS_INFO[os_name].copy() if chroot: #Unmount the filesystem. if CoreTools.unmount(mount_point) != 0: break #CoreTools.emergency_exit("Couldn't unmount "+partition+" after looking for" # + "operating systems on it! Please reboot your " # + "computer and try again.") #Remove the temporary mountpoint os.rmdir(mount_point) #Check that at least one OS was detected. if len(OS_INFO) >= 1: return OS_INFO, SYSTEM_INFO #Otherwise... return (False, False)
def filesystem_check(_type, manage_bootloader_function): """Quickly check all filesystems.""" logger.debug("filesystem_check(): Starting...") #Update Current Operation Text. wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Preparing for Filesystem Check...") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 10) wx.CallAfter(wx.GetApp().TopWindow.update_output_box, "\n###Preparing to do the Filesystem Check...###\n") #Determine which Disks are to be checked. filesystems_to_check = HelperBackendTools.find_checkable_file_systems() wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 30) #Find the length of the list (this is needed to update the progressbars). filesystems_to_check_length = len(filesystems_to_check) checked = 0 DialogTools.show_msg_dlg( kind="info", message="WxFixBoot will now perform the disk checks. " + "You may wish to open the terminal output box to view the " + "progress information.") #Run the check on the checkable Disks for disk in filesystems_to_check: #Gather info. logger.info("filesystem_check():: Checking " + disk + "...") wx.CallAfter(wx.GetApp().TopWindow.update_output_box, "\n###Checking Disk: " + disk + "###\n") wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Checking Disk: " + disk) wx.CallAfter( wx.GetApp().TopWindow.update_current_progress, 30 + ((50 // filesystems_to_check_length) * (checked + 1))) run_badblocks = False #Create a command list that will work based on the fstype of this Disk and the type of #check we're performing. If there aren't any use cases for the fstype, display a message #to the user and skip it. if _type == "Quick": if DISK_INFO[disk]["FileSystem"] == "jfs": exec_cmds = "fsck.jfs -vf " + disk elif DISK_INFO[disk]["FileSystem"] == "minix": exec_cmds = "fsck.minix -avf " + disk elif DISK_INFO[disk]["FileSystem"] == "reiserfs": exec_cmds = "fsck.reiserfs -apf " + disk elif DISK_INFO[disk]["FileSystem"] == "xfs": exec_cmds = "xfs_repair -Pvd " + disk elif DISK_INFO[disk]["FileSystem"] in ("hfs", "hfsplus"): exec_cmds = "fsck.hfsplus -fy " + disk elif DISK_INFO[disk]["FileSystem"] == "vfat": exec_cmds = "fsck.vfat -yv " + disk elif DISK_INFO[disk]["FileSystem"] in ('ext2', 'ext3', 'ext4', 'ext4dev'): exec_cmds = "fsck." + DISK_INFO[disk][ "FileSystem"] + " -yvf " + disk else: exec_cmds = "" logger.warning( "filesystem_check(): Skipping Disk: " + disk + ", as WxFixBoot doesn't support checking it yet...") DialogTools.show_msg_dlg( kind="error", message="The filesystem on Disk: " + disk + " could not be checked, as WxFixBoot doesn't support " + "checking it yet. " + disk + " will now be skipped.") else: #For disks that doesn't do bad sector checks with the normal FS checker, #run badblocks manually on them. if DISK_INFO[disk]["FileSystem"] == "jfs": exec_cmds = "fsck.jfs -vf " + disk run_badblocks = True elif DISK_INFO[disk]["FileSystem"] == "minix": exec_cmds = "fsck.minix -avf " + disk run_badblocks = True elif DISK_INFO[disk]["FileSystem"] == "reiserfs": exec_cmds = "fsck.reiserfs -apf " + disk run_badblocks = True elif DISK_INFO[disk]["FileSystem"] == "xfs": exec_cmds = "xfs_repair -Pvd " + disk run_badblocks = True elif DISK_INFO[disk]["FileSystem"] in ("hfs", "hfsplus"): exec_cmds = "fsck.hfsplus -fy " + disk run_badblocks = True elif DISK_INFO[disk]["FileSystem"] == "vfat": exec_cmds = "fsck.vfat -yvt " + disk elif DISK_INFO[disk]["FileSystem"] in ('ext2', 'ext3', 'ext4', 'ext4dev'): exec_cmds = "fsck." + DISK_INFO[disk][ "FileSystem"] + " -yvcf " + disk else: exec_cmds = "" DialogTools.show_msg_dlg( kind="info", message="The filesystem on Disk: " + disk + " could not be checked, as WxFixBoot doesn't support " + "checking it yet. " + disk + " will now be skipped.") #Run the command, and remount the Disk if needed. if exec_cmds != "": retval = CoreTools.start_process(exec_cmds, privileged=True) #Check the return values, and run the handler if needed. if retval == 0: #Success. logger.info("filesystem_check(): Checked Disk: " + disk + ". No Errors Found!") else: handle_filesystem_check_return_values( exec_cmds=exec_cmds, retval=retval, partition=disk, manage_bootloader_function=manage_bootloader_function) #Run bad blocks if requested. if run_badblocks: retval = CoreTools.start_process("badblocks -sv " + disk, privileged=True) #Check the return values, and run the handler if needed. if retval == 0: #Success. logger.info("filesystem_check(): Checked Disk: " + disk + " for bad sectors. " + "No Errors Found!") else: handle_filesystem_check_return_values( exec_cmds="badblocks -sv " + disk, retval=retval, partition=disk, manage_bootloader_function=manage_bootloader_function) if filesystems_to_check[disk]["Remount"]: logger.debug("filesystem_check(): Remounting Disk: " + disk + " Read-Write...") retval = CoreTools.mount_partition( partition=disk, mount_point=filesystems_to_check[disk]["MountPoint"]) if retval != 0: logger.warning( "filesystem_check(): Failed to remount " + disk + " after check. We probably need to reboot first. Never mind..." ) checked += 1 #Update Current Operation Text. wx.CallAfter(wx.GetApp().TopWindow.update_current_operation_text, message="Finished Filesystem Check!") wx.CallAfter(wx.GetApp().TopWindow.update_current_progress, 100) wx.CallAfter(wx.GetApp().TopWindow.update_output_box, "\n###Finished Filesystem Check!###\n")