def refresh_pacman_databases(self): """ Updates pacman databases """ # Init pyalpm try: pacman = pac.Pac("/etc/pacman.conf", self.callback_queue) except Exception as ex: template = "Can't initialize pyalpm. An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logging.error(message) raise InstallError(message) # Refresh pacman databases if not pacman.refresh(): logging.error("Can't refresh pacman databases.") txt = _("Can't refresh pacman databases.") raise InstallError(txt) try: pacman.release() del pacman except Exception as ex: template = "Can't release pyalpm. An exception of type {0} occured. Arguments:\n{1!r}" message = template.format(type(ex).__name__, ex.args) logging.error(message) raise InstallError(message)
def chroot_call(cmd, chroot_dir=DEST_DIR, fatal=False, msg=None, timeout=None, stdin=None): """ Runs command inside the chroot """ full_cmd = ['chroot', chroot_dir] for element in cmd: full_cmd.append(element) if not os.environ.get('CNCHI_RUNNING', False): os.environ['CNCHI_RUNNING'] = 'True' try: proc = subprocess.Popen( full_cmd, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout_data, stderr_data = proc.communicate(timeout=timeout) stdout_data = stdout_data.decode().strip() if stdout_data: logging.debug(stdout_data) return stdout_data except subprocess.TimeoutExpired as err: if proc: # The child process is not killed if the timeout expires, so in # order to cleanup let's kill the child process and finish communication proc.kill() proc.communicate() msg = "Timeout running the command {0}".format(err.cmd) logging.error(msg) if fatal: raise InstallError(err.output) else: log_exception_info() return False except subprocess.CalledProcessError as err: if msg: msg = "{0}: {1}".format(msg, err.output) else: msg = "Error running {0}: {1}".format(err.cmd, err.output) logging.error(msg) if fatal: raise InstallError(err.output) else: log_exception_info() return False except OSError as os_error: if msg: msg = "{0}: {1}".format(msg, os_error) else: msg = "Error running {0}: {1}".format(" ".join(full_cmd), os_error) logging.error(msg) if fatal: raise InstallError(os_error) else: log_exception_info() return False
def __init__(self, params, prev_page="user_info", next_page="slides", **kwargs): """ Init class ui """ super().__init__(self, params, name="summary", prev_page=prev_page, next_page=next_page, **kwargs) self.main_window = params['main_window'] if not self.main_window: raise InstallError("Can't get main window") scrolled_window = self.ui.get_object("scrolled_window") if scrolled_window: scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS) self.num_features = 0 self.process = None self.title = _("Review")
def sgdisk_new(device, part_num, label, size, hex_code): """ Helper function to call sgdisk --new (GPT) """ # --new: Create a new partition, numbered partnum, starting at sector start # and ending at sector end. # Parameters: partnum:start:end (zero in start or end means using default # value) # --typecode: Change a partition's GUID type code to the one specified by # hexcode. Note that hexcode is a gdisk/sgdisk internal # two-byte hexadecimal code. # You can obtain a list of codes with the -L option. # Parameters: partnum:hexcode # --change-name: Change the name of the specified partition. # Parameters: partnum:name # logging.debug(" ".join(cmd)) cmd = [ 'sgdisk', '--new={0}:0:+{1}M'.format(part_num, size), '--typecode={0}:{1}'.format(part_num, hex_code), '--change-name={0}:{1}'.format(part_num, label), device] try: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: txt = "Cannot create a new partition on device {0}. Command {1} has failed: {2}" txt = txt.format(device, err.cmd, err.output.decode()) logging.error(txt) txt = _( "Cannot create a new partition on device {0}. Command {1} has failed: {2}") txt = txt.format(device, err.cmd, err.output.decode()) raise InstallError(txt)
def parted_mkpart(device, ptype, start, end, filesystem=""): """ Helper function to call mkpart parted command """ # If start is < 0 we assume we want to mkpart at the start of the disk if start < 0: start_str = "1" else: start_str = "{0}MiB".format(start) # -1s means "end of disk" if end == "-1s": end_str = end else: end_str = "{0}MiB".format(end) cmd = [ 'parted', '--align', 'optimal', '--script', device, '--', 'mkpart', ptype, filesystem, start_str, end_str] try: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: txt = "Cannot create a new partition on device {0}. Command {1} has failed: {2}" txt = txt.format(device, err.cmd, err.output.decode()) logging.error(txt) txt = _( "Cannot create a new partition on device {0}. Command {1} has failed: {2}") txt = txt.format(device, err.cmd, err.output.decode()) raise InstallError(txt)
def popen(cmd, warning=True, error=False, fatal=False, msg=None, stdin=subprocess.PIPE): """ Helper function that calls Popen (useful if we need to use pipes) """ try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.STDOUT) return proc except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as err: if not msg: msg = "Error running {0}: {1}".format(err.cmd, err.output.decode()) else: msg = "{0}: {1}".format(msg, err.output.decode()) if not error and not fatal: if not warning: logging.debug(msg) else: logging.warning(msg) log_exception_info() else: logging.error(msg) if fatal: raise InstallError(msg) else: log_exception_info() return None
def popen(cmd, warning=True, error=False, fatal=False, msg=None, stdin=subprocess.PIPE): """ Helper function that calls Popen (useful if we need to use pipes) """ if not os.environ.get('CNCHI_RUNNING', False): os.environ['CNCHI_RUNNING'] = 'True' if not ensured_executable(cmd): logging.error('ensured_executable failed for cmd: %s', cmd) try: proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.STDOUT) return proc except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as err: if not msg: msg = "Error running {0}: {1}".format(err.cmd, err.output.decode()) else: msg = "{0}: {1}".format(msg, err.output.decode()) if not error and not fatal: if not warning: logging.debug(msg) else: logging.warning(msg) log_exception_info() else: logging.error(msg) if fatal: raise InstallError(msg) else: log_exception_info() return None
def sgdisk(command, device): """ Helper function to call sgdisk (GPT) """ cmd = ['sgdisk', "--{0}".format(command), device] try: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: logging.error("Command %s failed: %s", err.cmd, err.output.decode()) txt = _("Command {0} failed: {1}").format(err.cmd, err.output.decode()) raise InstallError(txt)
def get_install_screen(self): """ Returns installation screen page """ page = "installation_" + self.settings.get('partition_mode') install_screen = None try: install_screen = self.main_window.pages['disk_grp'][page] except (AttributeError, KeyError) as page_error: msg = "Can't find installation page called {0}: {1}" msg = msg.format(page, page_error) logging.error(msg) raise InstallError(msg) return install_screen
def call(cmd, warning=True, error=False, fatal=False, msg=None, timeout=None, stdin=None, debug=True): """ Helper function to make a system call warning: If true will log a warning message if an error is detected error: If true will log an error message if an error is detected fatal: If true will log an error message AND will raise an InstallError exception msg: Error message to log (if empty the command called will be logged) """ output = None if not os.environ.get('CNCHI_RUNNING', False): os.environ['CNCHI_RUNNING'] = 'True' if not ensured_executable(cmd): logging.error('ensured_executable failed for cmd: %s', cmd) try: output = subprocess.check_output(cmd, stdin=stdin, stderr=subprocess.STDOUT, timeout=timeout) output = output.decode() if output and debug: _output = output.strip('\n') logging.debug(_output) return output except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as err: err_output = err.output.decode().strip("\n") if not msg: msg = "Error running {0}: {1}".format(err.cmd, err_output) else: msg = "{0}: {1}".format(msg, err_output) if not error and not fatal: if not warning or "['umount', '-l'," in msg: logging.debug(msg) else: logging.warning(msg) log_exception_info() else: logging.error(msg) if fatal: raise InstallError(msg) else: log_exception_info() return False
def parted_mklabel(device, label_type="msdos"): """ Helper function to call mktable parted command """ cmd = [ "parted", "--align", "optimal", "--script", device, "mklabel", label_type] try: subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: txt = ("Cannot create a new partition table on device {0}. " "Command {1} failed: {2}") txt = txt.format(device, err.cmd, err.output.decode()) logging.error(txt) txt = _("Cannot create a new partition table on device {0}. " "Command {1} failed: {2}") txt = txt.format(device, err.cmd, err.output.decode()) raise InstallError(txt)
def call(cmd, warning=True, error=False, fatal=False, msg=None, timeout=None, stdin=None, debug=True): """ Helper function to make a system call warning: If true will log a warning message if an error is detected error: If true will log an error message if an error is detected fatal: If true will log an error message AND will raise an InstallError exception msg: Error message to log (if empty the command called will be logged) """ output = None try: output = subprocess.check_output(cmd, stdin=stdin, stderr=subprocess.STDOUT, timeout=timeout) output = output.decode() if output and debug: output = output.strip('\n') logging.debug(output) return output except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as err: err_output = err.output.decode().strip("\n") if not msg: msg = "Error running {0}: {1}".format(err.cmd, err_output) else: msg = "{0}: {1}".format(msg, err_output) if not error and not fatal: if not warning: logging.debug(msg) else: logging.warning(msg) log_exception_info() else: logging.error(msg) if fatal: raise InstallError(msg) else: log_exception_info() return False
def create_zfs(self, solaris_partition_number): """ Setup ZFS system """ # Empty DEST_DIR or zfs pool will fail to mount on it # (this will delete preexisting installing attempts, too) if os.path.exists(DEST_DIR): self.clear_dest_dir() device_paths = self.zfs_options["device_paths"] if not device_paths: txt = _("No devices were selected for the ZFS pool") raise InstallError(txt) # Make sure the ZFS modules are loaded call(["modprobe", "zfs"]) # Using by-id (recommended) does not work atm # https://github.com/zfsonlinux/zfs/issues/3708 # Can't use the whole first disk, just the dedicated zfs partition device_paths[0] = self.get_partition_path(device_paths[0], solaris_partition_number) line = ", ".join(device_paths) logging.debug("Cnchi will create a ZFS pool using %s devices", line) # Just in case... if os.path.exists("/etc/zfs/zpool.cache"): os.remove("/etc/zfs/zpool.cache") try: os.mkdir(DEST_DIR, mode=0o755) except OSError: pass pool_name = self.zfs_options["pool_name"] pool_type = self.zfs_options["pool_type"] if not self.pool_name_is_valid(pool_name): txt = _( "Pool name is invalid. It must contain only alphanumeric characters (a-zA-Z0-9_), " "hyphens (-), colons (:), and/or spaces ( ). Names starting with the letter 'c' " "followed by a number (c[0-9]) are not allowed. The following names are also not " "allowed: 'mirror', 'raidz', 'spare', 'log'.") raise InstallError(txt) # Create zpool self.create_zfs_pool(pool_name, pool_type, device_paths) # Set the mount point of the root filesystem self.set_zfs_mountpoint(pool_name, "/") # Set the bootfs property on the descendant root filesystem so the # boot loader knows where to find the operating system. cmd = ["zpool", "set", "bootfs={0}".format(pool_name), pool_name] call(cmd, fatal=True) # Create zpool.cache file cmd = ["zpool", "set", "cachefile=/etc/zfs/zpool.cache", pool_name] call(cmd, fatal=True) if self.settings.get('use_home'): # Create home zvol logging.debug("Creating zfs subvolume 'home'") self.create_zfs_vol(pool_name, "home") self.set_zfs_mountpoint("{0}/home".format(pool_name), "/home") # ZFS automounts, we have to unmount /install/home and delete it, # otherwise we won't be able to import the zfs pool home_path = "{0}/home".format(DEST_DIR) call(["zfs", "umount", home_path], warning=False) shutil.rmtree(path=home_path, ignore_errors=True) # Create swap zvol (it has to be named "swap") swap_size = self.get_swap_size(pool_name) self.create_zfs_vol(pool_name, "swap", swap_size) # Wait until /dev initialized correct devices call(["udevadm", "settle"]) call(["sync"]) # Export the pool # Makes the kernel to flush all pending data to disk, writes data to # the disk acknowledging that the export was done, and removes all # knowledge that the storage pool existed in the system logging.debug("Exporting pool %s...", pool_name) cmd = ["zpool", "export", "-f", pool_name] call(cmd, fatal=True) # Let's get the id of the pool (to import it) pool_id, _status = self.get_pool_id(pool_name) if not pool_id: # Something bad has happened. Will use the pool name instead. logging.warning("Can't get %s zpool id", pool_name) pool_id = pool_name # Save pool id self.settings.set("zfs_pool_id", pool_id) # Finally, re-import the pool by-id # DEST_DIR must be empty or importing will fail! logging.debug("Importing pool %s (%s)...", pool_name, pool_id) cmd = [ "zpool", "import", "-f", "-d", "/dev/disk/by-id", "-R", DEST_DIR, pool_id ] call(cmd, fatal=True) # Copy created cache file to destination try: dst_dir = os.path.join(DEST_DIR, "etc/zfs") os.makedirs(dst_dir, mode=0o755, exist_ok=True) src = "/etc/zfs/zpool.cache" dst = os.path.join(dst_dir, "zpool.cache") shutil.copyfile(src, dst) except OSError as copy_error: logging.warning(copy_error) # Store hostid hostid = call(["hostid"]) if hostid: hostid_path = os.path.join(DEST_DIR, "etc/hostid") with open(hostid_path, "w") as hostid_file: hostid_file.write("{0}\n".format(hostid))
def create_zfs_pool(self, pool_name, pool_type, device_paths): """ Create zpool """ if pool_type not in self.pool_types.values(): raise InstallError("Unknown pool type: {0}".format(pool_type)) #for device_path in device_paths: # cmd = ["zpool", "labelclear", device_path] # call(cmd) cmd = ["zpool", "create"] if self.zfs_options["force_4k"]: cmd.extend(["-o", "ashift=12"]) cmd.extend(["-m", DEST_DIR, pool_name]) pool_type = pool_type.lower().replace("-", "") if pool_type in ["none", "stripe"]: # Add first device cmd.append(device_paths[0]) elif pool_type == "mirror": if len(device_paths) > 2 and len(device_paths) % 2 == 0: # Try to mirror pair of devices # (mirrors of two devices each) for i, k in zip(device_paths[0::2], device_paths[1::2]): cmd.append(pool_type) cmd.extend([i, k]) else: cmd.append(pool_type) cmd.extend(device_paths) else: cmd.append(pool_type) cmd.extend(device_paths) # Wait until /dev initialized correct devices call(["udevadm", "settle"]) call(["sync"]) logging.debug("Creating zfs pool %s...", pool_name) if call(cmd, warning=False) is False: # Try again, now with -f cmd.insert(2, "-f") if call(cmd, warning=False) is False: # Wait 10 seconds more and try again. # (Waiting a bit sometimes works) time.sleep(10) call(cmd, fatal=True) # Wait until /dev initialized correct devices call(["udevadm", "settle"]) call(["sync"]) if pool_type == "stripe": # Add the other devices that were left out cmd = ["zpool", "add", pool_name] cmd.extend(device_paths[1:]) call(cmd, fatal=True) logging.debug("Pool %s created.", pool_name)
def run(self): key_files = ["/tmp/.keyfile-root", "/tmp/.keyfile-home"] # Partition sizes are expressed in MiB # Get just the disk size in MiB device = self.auto_device device_name = os.path.split(device)[1] size_path = os.path.join("/sys/block", device_name, 'size') base_path = os.path.split(size_path)[0] if os.path.exists(size_path): logical_path = os.path.join(base_path, "queue/logical_block_size") with open(logical_path, 'r') as f: logical_block_size = int(f.read()) with open(size_path, 'r') as f: size = int(f.read()) disk_size = ((logical_block_size * (size - 68)) / 1024) / 1024 else: logging.error("Cannot detect %s device size", device) txt = _( "Setup cannot detect size of your device, please use advanced " "installation routine for partitioning and mounting devices.") raise InstallError(txt) start_part_sizes = 1 part_sizes = self.get_part_sizes(disk_size, start_part_sizes) self.log_part_sizes(part_sizes) # Disable swap and unmount all partitions inside dest_dir unmount_all_in_directory(self.dest_dir) # Disable swap and unmount all partitions of device unmount_all_in_device(device) # Remove lvm in destination device remove_lvm(device) # Close luks devices in destination device close_reborn_luks_devices() printk(False) # WARNING: # Our computed sizes are all in mebibytes (MiB) i.e. powers of 1024, not metric megabytes. # These are 'M' in sgdisk and 'MiB' in parted. # If you use 'M' in parted you'll get MB instead of MiB, and you're gonna have a bad time. if self.gpt: # Clean partition table to avoid issues! wrapper.sgdisk("zap-all", device) # Clear all magic strings/signatures - mdadm, lvm, partition tables etc. wrapper.dd("/dev/zero", device, bs=512, count=2048) wrapper.wipefs(device) # Create fresh GPT wrapper.sgdisk("clear", device) wrapper.parted_mklabel(device, "gpt") # Inform the kernel of the partition change. Needed if the hard disk had a MBR partition table. err_msg = "Error informing the kernel of the partition change." call(["partprobe", device], msg=err_msg, fatal=True) part_num = 1 if not self.uefi: # We don't allow BIOS+GPT right now, so this code will be never executed # We leave here just for future reference # Create BIOS Boot Partition # GPT GUID: 21686148-6449-6E6F-744E-656564454649 # This partition is not required if the system is UEFI based, # as there is no such embedding of the second-stage code in that case wrapper.sgdisk_new(device, part_num, "BIOS_BOOT", 2, "EF02") part_num += 1 if self.bootloader == "grub2": # Create EFI System Partition (ESP) # GPT GUID: C12A7328-F81F-11D2-BA4B-00A0C93EC93B wrapper.sgdisk_new(device, part_num, "UEFI_SYSTEM", part_sizes['efi'], "EF00") part_num += 1 # Create Boot partition if self.bootloader in ["systemd-boot", "refind"]: wrapper.sgdisk_new(device, part_num, "REBORN_BOOT", part_sizes['boot'], "EF00") else: wrapper.sgdisk_new(device, part_num, "REBORN_BOOT", part_sizes['boot'], "8300") part_num += 1 if self.lvm: # Create partition for lvm (will store root, swap and home (if desired) logical volumes) wrapper.sgdisk_new(device, part_num, "REBORN_LVM", part_sizes['lvm_pv'], "8E00") part_num += 1 else: wrapper.sgdisk_new(device, part_num, "REBORN_ROOT", part_sizes['root'], "8300") part_num += 1 if self.home: wrapper.sgdisk_new(device, part_num, "REBORN_HOME", part_sizes['home'], "8302") part_num += 1 wrapper.sgdisk_new(device, part_num, "REBORN_SWAP", 0, "8200") output = call(["sgdisk", "--print", device]) logging.debug(output) else: # DOS MBR partition table # Start at sector 1 for 4k drive compatibility and correct alignment # Clean partitiontable to avoid issues! wrapper.dd("/dev/zero", device, bs=512, count=2048) wrapper.wipefs(device) # Create DOS MBR wrapper.parted_mklabel(device, "msdos") # Create boot partition (all sizes are in MiB) # if start is -1 wrapper.parted_mkpart assumes that our partition starts at 1 (first partition in disk) start = -1 end = part_sizes['boot'] wrapper.parted_mkpart(device, "primary", start, end) # Set boot partition as bootable wrapper.parted_set(device, "1", "boot", "on") if self.lvm: # Create partition for lvm (will store root, home (if desired), and swap logical volumes) start = end # end = start + part_sizes['lvm_pv'] end = "-1s" wrapper.parted_mkpart(device, "primary", start, end) # Set lvm flag wrapper.parted_set(device, "2", "lvm", "on") else: # Create root partition start = end end = start + part_sizes['root'] wrapper.parted_mkpart(device, "primary", start, end) if self.home: # Create home partition start = end end = start + part_sizes['home'] wrapper.parted_mkpart(device, "primary", start, end) # Create an extended partition where we will put our swap partition start = end # end = start + part_sizes['swap'] end = "-1s" wrapper.parted_mkpart(device, "extended", start, end) # Now create a logical swap partition start += 1 end = "-1s" wrapper.parted_mkpart(device, "logical", start, end, "linux-swap") printk(True) # Wait until /dev initialized correct devices call(["udevadm", "settle"]) devices = self.get_devices() if self.gpt and self.bootloader == "grub2": logging.debug("EFI: %s", devices['efi']) logging.debug("Boot: %s", devices['boot']) logging.debug("Root: %s", devices['root']) if self.home: logging.debug("Home: %s", devices['home']) logging.debug("Swap: %s", devices['swap']) if self.luks: setup_luks(devices['luks_root'], "cryptReborn", self.luks_password, key_files[0]) if self.home and not self.lvm: setup_luks(devices['luks_home'], "cryptRebornHome", self.luks_password, key_files[1]) if self.lvm: logging.debug("Cnchi will setup LVM on device %s", devices['lvm']) err_msg = "Error creating LVM physical volume in device {0}" err_msg = err_msg.format(devices['lvm']) cmd = ["pvcreate", "-f", "-y", devices['lvm']] call(cmd, msg=err_msg, fatal=True) err_msg = "Error creating LVM volume group in device {0}" err_msg = err_msg.format(devices['lvm']) cmd = ["vgcreate", "-f", "-y", "RebornVG", devices['lvm']] call(cmd, msg=err_msg, fatal=True) # Fix issue 180 # Check space we have now for creating logical volumes cmd = ["vgdisplay", "-c", "RebornVG"] vg_info = call(cmd, fatal=True) # Get column number 12: Size of volume group in kilobytes vg_size = int(vg_info.split(":")[11]) / 1024 if part_sizes['lvm_pv'] > vg_size: logging.debug("Real RebornVG volume group size: %d MiB", vg_size) logging.debug("Reajusting logical volume sizes") diff_size = part_sizes['lvm_pv'] - vg_size part_sizes = self.get_part_sizes(disk_size - diff_size, start_part_sizes) self.log_part_sizes(part_sizes) # Create LVM volumes err_msg = "Error creating LVM logical volume" size = str(int(part_sizes['root'])) cmd = [ "lvcreate", "--name", "RebornRoot", "--size", size, "RebornVG" ] call(cmd, msg=err_msg, fatal=True) if not self.home: # Use the remainig space for our swap volume cmd = [ "lvcreate", "--name", "RebornSwap", "--extents", "100%FREE", "RebornVG" ] call(cmd, msg=err_msg, fatal=True) else: size = str(int(part_sizes['swap'])) cmd = [ "lvcreate", "--name", "RebornSwap", "--size", size, "RebornVG" ] call(cmd, msg=err_msg, fatal=True) # Use the remaining space for our home volume cmd = [ "lvcreate", "--name", "RebornHome", "--extents", "100%FREE", "RebornVG" ] call(cmd, msg=err_msg, fatal=True) # We have all partitions and volumes created. Let's create its filesystems with mkfs. mount_points = { 'efi': '/boot/efi', 'boot': '/boot', 'root': '/', 'home': '/home', 'swap': '' } labels = { 'efi': 'UEFI_SYSTEM', 'boot': 'RebornBoot', 'root': 'RebornRoot', 'home': 'RebornHome', 'swap': 'RebornSwap' } fs_devices = self.get_fs_devices() # Note: Make sure the "root" partition is defined first! self.mkfs(devices['root'], fs_devices[devices['root']], mount_points['root'], labels['root']) self.mkfs(devices['swap'], fs_devices[devices['swap']], mount_points['swap'], labels['swap']) if self.gpt and self.bootloader in ["refind", "systemd-boot"]: # Format EFI System Partition (ESP) with vfat (fat32) self.mkfs(devices['boot'], fs_devices[devices['boot']], mount_points['boot'], labels['boot'], "-F 32") else: self.mkfs(devices['boot'], fs_devices[devices['boot']], mount_points['boot'], labels['boot']) # Note: Make sure the "boot" partition is defined before the "efi" one! if self.gpt and self.bootloader == "grub2": # Format EFI System Partition (ESP) with vfat (fat32) self.mkfs(devices['efi'], fs_devices[devices['efi']], mount_points['efi'], labels['efi'], "-F 32") if self.home: self.mkfs(devices['home'], fs_devices[devices['home']], mount_points['home'], labels['home']) # NOTE: encrypted and/or lvm2 hooks will be added to mkinitcpio.conf in process.py if necessary # NOTE: /etc/default/grub, /etc/stab and /etc/crypttab will be modified in process.py, too. if self.luks and self.luks_password == "": # Copy root keyfile to boot partition and home keyfile to root partition # user will choose what to do with it # THIS IS NONSENSE (BIG SECURITY HOLE), BUT WE TRUST THE USER TO FIX THIS # User shouldn't store the keyfiles unencrypted unless the medium itself is reasonably safe # (boot partition is not) err_msg = "Can't copy LUKS keyfile to the installation device." os.chmod(key_files[0], 0o400) boot_path = os.path.join(self.dest_dir, "boot") cmd = ['mv', key_files[0], boot_path] call(cmd, msg=err_msg) if self.home and not self.lvm: os.chmod(key_files[1], 0o400) luks_dir = os.path.join(self.dest_dir, 'etc/luks-keys') os.makedirs(luks_dir, mode=0o755, exist_ok=True) cmd = ['mv', key_files[1], luks_dir] call(cmd, msg=err_msg)
def mkfs(self, device, fs_type, mount_point, label_name, fs_options="", btrfs_devices=""): """ We have two main cases: "swap" and everything else. """ logging.debug("Will format device %s as %s", device, fs_type) if fs_type == "swap": err_msg = "Can't activate swap in {0}".format(device) swap_devices = call(["swapon", "-s"], msg=err_msg) if device in swap_devices: call(["swapoff", device], msg=err_msg) cmd = ["mkswap", "-L", label_name, device] call(cmd, msg=err_msg) cmd = ["swapon", device] call(cmd, msg=err_msg) else: mkfs = { "xfs": "mkfs.xfs {0} -L {1} -f {2}".format(fs_options, label_name, device), "jfs": "yes | mkfs.jfs {0} -L {1} {2}".format(fs_options, label_name, device), "reiserfs": "yes | mkreiserfs {0} -l {1} {2}".format( fs_options, label_name, device), "ext2": "mkfs.ext2 -q {0} -F -L {1} {2}".format( fs_options, label_name, device), "ext3": "mkfs.ext3 -q {0} -F -L {1} {2}".format( fs_options, label_name, device), "ext4": "mkfs.ext4 -q {0} -F -L {1} {2}".format( fs_options, label_name, device), "btrfs": "mkfs.btrfs {0} -L {1} {2}".format(fs_options, label_name, btrfs_devices), "nilfs2": "mkfs.nilfs2 {0} -L {1} {2}".format(fs_options, label_name, device), "ntfs-3g": "mkfs.ntfs {0} -L {1} {2}".format(fs_options, label_name, device), "vfat": "mkfs.vfat {0} -n {1} {2}".format(fs_options, label_name, device), "fat32": "mkfs.vfat {0} -n {1} {2}".format(fs_options, label_name, device), "f2fs": "mkfs.f2fs {0} -l {1} {2}".format(fs_options, label_name, device) } # Make sure the fs type is one we can handle if fs_type not in mkfs.keys(): txt = _("Unknown filesystem type {0}").format(fs_type) raise InstallError(txt) command = mkfs[fs_type] err_msg = "Can't create filesystem {0}".format(fs_type) call(command.split(), msg=err_msg, fatal=True) # Flush filesystem buffers call(["sync"]) # Create our mount directory path = self.dest_dir + mount_point os.makedirs(path, mode=0o755, exist_ok=True) # Mount our new filesystem mopts = "rw,relatime" if fs_type == "ext4": mopts = "rw,relatime,data=ordered" elif fs_type == "btrfs": mopts = 'rw,relatime,space_cache,autodefrag,inode_cache' err_msg = "Error trying to mount {0} in {1}".format(device, path) cmd = ["mount", "-t", fs_type, "-o", mopts, device, path] call(cmd, msg=err_msg, fatal=True) # Change permission of base directories to avoid btrfs issues if mount_point == "/tmp": mode = 0o1777 elif mount_point == "/root": mode = 0o750 else: mode = 0o755 os.chmod(path, mode) fs_uuid = fs.get_uuid(device) fs_label = fs.get_label(device) msg = "Device details: %s UUID=%s LABEL=%s" logging.debug(msg, device, fs_uuid, fs_label)