def update_initramfs(self): """ Updates the initramfs. """ m.verbose("Updating the initramfs...") m.sexec("update-initramfs -u -k all")
def rename(self, new): """Renames the Volume Group. new is the new group's name.""" m.sexec("vgrename %(name)s %(new)s" % {"name":self.name, "new":new}) self.name = new
def format_partition_for_real(obj, fs): """ Uses mkfs.* to format partition. """ # Get an appropriate frontend frontend = get_supported_filesystems()[fs] _app = frontend[0] # Application (e.g /sbin/mkfs.ext4) _opt = frontend[1] # Options of the application. # Umount... if is_mounted(obj.path): umount(parted_part=obj) _opt = "%s %s" % (obj.path, _opt) # In some cases, a freshly committed Disk object will temporairly # make the partitions unavailable. # Running partprobe resolves this, but will slow down the process # a bit. try: m.sexec("partprobe") except: pass # BEGIN FORMATTING!!!!111111!!!!!!!!!!!!!1111111111111111 mkfs = m.execute("%s %s" % (_app, _opt)) mkfs.start() # START!!!111111111!!!!!!!!!!!!!!!111111111111111 # Return object to frontend, it should handle all. return mkfs
def create(self, size): """Creates the logical volume on self.vgroup with size 'size'.""" # Size comes in as MB (S.I.), we need to transform them to kibibytes... size *= 1000 # KB size /= 1.024 # KiB size = int(size)-1 # round and ensure we aren't in excess #size = str(size) + "K" # Do the same with the extents unit = self.vgroup.infos["extentsize"] unit *= 1000 # KB unit /= 1.024 # KiB unit = int(unit)-1 # round and ensure we aren't in excess free = int(self.vgroup.infos["extentfree"])*unit # Compare the size with the unit if size > free: # More than free, use the maximum allowed size = free size = str(size) + "k" m.sexec("lvcreate --name %(name)s --size %(size)s %(vgroup)s" % {"name":self.name, "size":size, "vgroup":self.vgroup.name}) self.reload_infos()
def umount(parted_part=None, path=None, tries=0): """ Unmounts a partition. You can use parted_part or path. parted_part is a Partition object of pyparted. path is a str that contains the device in /dev (e.g. '/dev/sda1') """ # Check args if parted_part: path = parted_part.path elif not path: # Not parted_part, nor path. raise m.UserError("mount_partition called without parted_part and without path!") # Check if it is mounted... if not is_mounted(path): raise m.UserError("%s is not mounted!" % path) # Unmount. try: m.sexec("umount %s" % path) except m.CmdError, e: # Failed, retry after two seconds time.sleep(2) if tries < 5: # max 5 tries return umount(parted_part=parted_part, path=path, tries=tries+1) else: raise e
def rename(self, new): """Renames the Logical Volume. new is the new volume's name.""" m.sexec("lvrename %(vgroup)s %(name)s %(new)s" % {"vgroup":self.vgroup.name, "name":self.name, "new":new}) self.name = new self.reload_infos()
def format(self): """ Formats the previously created persistent filesystem. """ path = self.main_settings["target"] + self.settings["path"] # os.path.join doesn't work if second argument begins with / image = os.path.join(path, "persistence-%s" % (self.settings["suffix"])) # Format m.sexec("mkfs.ext2 -F %s" % image)
def disable(self): """ Disables the LogicalVolume. """ if os.path.exists(self.path): # Ensure it is umounted... if is_mounted(self.mapper_path): umount(path=self.mapper_path) m.sexec("lvchange -a n %s" % self.path)
def enable(self): """ Enables the VolumeGroup. """ if not os.path.exists(self.path): m.sexec("vgchange -a y %s" % self.name) # Enable every LV... for lv in self.logicalvolumes: lv.enable()
def create_ssl_certs(self): """ Creates the missing SSL certs. """ if os.path.exists("/var/lib/dpkg/info/ssl-cert.list"): # FIXME: saner check? m.verbose("Creating SSL certs...") m.sexec("make-ssl-cert generate-default-snakeoil --force-overwrite")
def disable(self): """ Disables the VolumeGroup. """ if os.path.exists(self.path): m.sexec("vgchange -a n %s" % self.name) # Disable every LV... for lv in self.logicalvolumes: lv.disable()
def create(self): """Creates the Physical Volume.""" if type(self.pv) == pa.Disk: # If we are initializing a disk, we need to erase the partition table # Using the good old dd to do so. m.sexec("dd if=/dev/zero of=%s bs=512 count=1" % self.pv) m.sexec("pvcreate --force %s" % self.pv)
def user_commit(self): """ Creates the user. """ # Create and chmod /etc/passwd- (temporary workaround) asd = open("/etc/passwd-","w") asd.close() os.chmod("/etc/passwd-",0600) # Ok... now invoking user-setup to make the changes we defined before... m.sexec("/usr/lib/user-setup/user-setup-apply")
def close(self): """ Closes the device. """ # Bugfix if not self.path: return # Ensure we have it unmounted... if lib.is_mounted(self.path): lib.umount(path=self.path) # Then close... m.sexec("cryptsetup luksClose %s" % self.path)
def zramcfg(self): """ Configures zram via zramcfg. """ # Get TotalMem size with open("/proc/meminfo") as mem: MemTotal = int(mem.readline().rstrip("\n").split(" ")[-2])/1024 if not os.path.exists("/usr/bin/zramcfg") or not self.moduleclass.settings["zram"] or not MemTotal <= ZRAM_LIMIT: return m.sexec("/usr/bin/zramcfg")
def remove_virtualbox(self): """ Removes VirtualBox-related packages. """ # FIXME: New releases of linstaller should handle better the package checking. try: for pkg in self.settings["remove-virtualbox.inst"].split(" "): m.sexec("dpkg -l %s &> /dev/null" % pkg, shell=True) except: return m.sexec("apt-get remove --yes --force-yes --purge %s" % self.settings["remove-virtualbox"])
def autoremove(self): """ Mark lvm2 as manually installed for now, and run apt-get autoremove """ try: m.sexec("apt-mark manual lvm2") except: pass if not self.moduleclass.settings["autoremove"]: pass else: m.sexec("apt-get autoremove --yes")
def select(self, set, isLast=False): """ Selects the fastest mirror using mirrorselect. """ verbose("Running mirrorselect with set %s..." % set) # Create arguments args = [] args.append("-s %s" % set) # Set args.append("-n") # Non-interactive if self.moduleclass.modules_settings["mirrorselect"]["enable_sources"]: args.append("-o") # Enable sources if not isLast: args.append("-u") # Do not apt-get update m.sexec("/usr/bin/mirrorselect %s" % " ".join(args))
def resize(self, size, type): """Resizes the Logical Volume.""" # Size comes in as MB (S.I.), we need to transform them to kibibytes... size *= 1000 # KB size /= 1.024 # KiB size = int(size)-1 # round and ensure we aren't in excess #size = str(size) + "K" size = str(size) + "k" m.sexec("lvresize --force --size %(size)s %(path)s" % {"size":size, "path":self.path}) self.reload_infos()
def install(self): """ Installs the bootloader on the specified device. """ target = self.settings["target"] if not target: # No target, we should get one. try: target = self.modules_settings["partdisks"]["root"] except: # We can't get a target raise m.UserError("Please specify target device.") # Get partition part = lib.return_partition(target) if part == None: raise m.UserError("Target device %s not found." % target) directory = os.path.join(self.main_settings["target"], "syslinux") bootloader = self.settings["bootloader"] if not bootloader: # We should get the bootloader ourselves. # What this means? We need to check for the partition type and set the appropiate bootloader. fs = part.fileSystem.type if fs in ("fat32"): bootloader = "syslinux" elif fs in ("ext2","ext3","ext4"): args = "-i '%(location)s'" % {"location":target} bootloader = "extlinux" if bootloader == "syslinux": args = "-i -d '%(dir)s' '%(location)s'" % {"dir":directory,"location":target} elif bootloader == "extlinux": # Generate extlinux configuration file (FIXME) with open(os.path.join(directory, "extlinux.cfg"), "w") as f: f.write("include syslinux.cfg\n") # Install MBR (warning: we do not make backups! Are they needed on USB drives MBR?) # FIXME: maybe find a cooler way to do this? m.sexec("dd if=/usr/lib/extlinux/mbr.bin of='%s' bs=440 count=1" % lib.return_device(target)) args = "-i '%(dir)s'" % {"dir":directory} verbose("Selected location: %s" % target) m.sexec("%(bootloader)s %(args)s" % {"bootloader":bootloader, "args":args}) # Make partition bootable... verbose("Making partition bootable...") lib.setFlag(part, "boot") lib.commit(part, (target)) # Commit
def format(self, password, cipher="aes-xts-plain64", keysize=512): """ Formats the device and sets password as the drive's password. """ # Umount lib.umount_bulk(self.string_device) # Try to close try: self.close() except m.CmdError: pass # Ugly as hell m.sexec("echo '%(password)s' | cryptsetup luksFormat --cipher %(cipher)s --key-size %(keysize)s %(device)s" % {"password":password, "device":self.string_device, "cipher":cipher, "keysize":keysize})
def prechecks(self): """ Checks if mirrorselect exists and a working internet connection is present. """ if not os.path.exists("/usr/bin/mirrorselect"): verbose("mirrorselect is not installed.") return False try: m.sexec("ping -c1 www.google.com") except: # No connection verbose("A working internet connection is not present.") return False return True
def random_fill(self, type=FillQuality.LOW): """ Fills the device with random data. type is an object from the FillQuality enum. It returns the process object to the frontend. """ # Umount lib.umount_bulk(self.string_device) if type == FillQuality.LOW: m.sexec("badblocks -c 10240 -s -w -t random -v %s" % self.string_device) elif type == FillQuality.HIGH: m.sexec("dd if=/dev/urandom of=%s" % self.string_device)
def on_module_change(self): """ Seeds items when we change module. """ # Preseed changes self.settings["language"] = self.get_selected_locale() self.settings["layout"] = self.get_selected_layouts() self.settings["model"] = self.get_selected_model() self.settings["variant"] = self.get_selected_variant() # The following is commented because it doesn't work fully. # (Yeah, this is a subtler way to say FIXME!!!111!!one!!eleven!) # # Set language, if we should #norm = locale.get_best_locale(self.settings["language"]) #current = locale_module.getlocale() #if current == (None, None): # current = None #else: # current = ".".join(current) #if current != norm: # try: # verbose("Setting installer language to %s (normalized: %s, current: %s)" % (self.settings["language"], norm, current)) # # locale.set(norm, generateonly=True) # # os.environ["LANG"] = norm # # # Also rebuild pages # self.objects["parent"].build_pages(replacepage=True, newlocale=norm) # # except: # verbose("Unable to set locale to %s, leaving locale unchanged." % norm) # Set keyboard layout kargs = ["setxkbmap", self.settings["layout"][0]] if self.settings["model"]: kargs.append("-model %s" % self.settings["model"]) if self.settings["variant"]: kargs.append("-variant %s" % self.settings["variant"]) try: # Warning: this will change the keyboard layout *globally* sexec(" ".join(kargs), shell=False) except: verbose("Unable to change the keyboard layout.") verbose("Selected language: %s" % self.settings["language"]) verbose("Selected keyboard: %s (model %s, variant %s)" % (self.settings["layout"], self.settings["model"], self.settings["variant"]))
def extend(self, devices): """Extends the Volume Group. devices is a tuple which contains the list of devices to include into the VG.""" if not type(devices) == tuple and not type(devices) == list: devices = (devices,) _devices = [] for device in devices: if type(device) == str: name = device else: name = device.pv _devices.append(name) m.sexec("vgextend %(name)s %(devices)s" % {"name":self.name, "devices":" ".join(_devices)})
def reduce(self, devices): """Reduces the Volume Group. devices is a tuple which contains the list of devices to remove from the VG.""" if not type(devices) == tuple and not type(devices) == list: devices = (devices,) _devices = [] for device in devices: if type(device) == str: name = device else: name = device.pv _devices.append(name) m.sexec("vgreduce %(name)s %(devices)s" % {"name":self.name, "devices":" ".join(_devices)})
def set_kernel(self): """ Final set-up of the kernel """ # Get the kernel package installed kernel_package = False re_minimal = re.compile("^linux-image-\d+\.\d+\.\d+\-\d+-.*$") for pkg in cache.keys(): if re_minimal.match(pkg) and cache[pkg].is_installed: kernel_package = pkg break if not kernel_package: raise m.UserError("Unable to determine the correct kernel.") # Rename the generic vmlinuz that we previously copied to /boot version = kernel_package.replace("linux-image-", "") shutil.move("/boot/vmlinuz", "/boot/vmlinuz-%s" % version) # Update initramfs m.sexec("update-initramfs -c -k %s" % version)
def bootstrap(self): """ Actually run the bootstrap. """ is_insecure = self.modules_settings["thewall"]["insecure"] is_foreign = False # FIXME! arch = self.modules_settings["thewall"]["arch"] areas = self.settings["areas"].split(" ") bootstrap_args = ["--arch=%s" % arch, "--components=%s" % ",".join(areas)] if is_foreign: bootstrap_args.append("--foreign") if is_insecure: bootstrap_args.append("--no-check-gpg") # Execute debootstrap... verbose("Executing debootstrap...") m.sexec("debootstrap %(options)s \"%(distro)s\" \"%(target)s\" \"%(mirror)s\"" % { "options":" ".join(bootstrap_args), "distro":self.settings["distro"], "target":self.main_settings["target"], "mirror":self.settings["mirror"] } ) if is_foreign: # FIXME! pass # Remove newly created hosts file... os.remove(os.path.join(self.main_settings["target"], "etc/hosts")) # Remove package cache... base = os.path.join(self.main_settings["target"], "var/cache/apt/archives") for item in os.listdir(base): if item.endswith(".deb"): os.remove(os.path.join(base, item))
def crypttab(self): """ Generates /etc/crypttab. """ if len(crypt.LUKSdevices) == 0: return with open("/etc/crypttab", "w") as f: for device, obj in crypt.LUKSdevices.items(): # See if the device is a physical volume, otherwise # we will not touch it... if not obj.mapper_path in lvm.PhysicalVolumes: continue UUID = lib.get_UUID(device) f.write("%(name)s UUID=%(UUID)s none luks\n" % {"name":obj.crypt_name, "UUID":UUID}) # Set proper owner and permissions on the file os.chown("/etc/crypttab", 0, 0) os.chmod("/etc/crypttab", 0744) # Also update-initramfs to make sure we include cryptsetup & family # into the initramfs m.sexec("update-initramfs -u -k all")
def mount_partition(parted_part=None, path=None, opts=False, typ=None, target=False, check=True): """ Mounts a partition. You can use parted_part or path. parted_part is a Partition object of pyparted. path is a str that contains the device in /dev (e.g. '/dev/sda1') """ # Check args if parted_part: path = parted_part.path elif not path: # Not parted_part, nor path. raise m.UserError("mount_partition called without parted_part and without path!") # Check if path exists... if path.startswith("/") and not os.path.exists(path): raise m.UserError("%s does not exist!" % path) # Generate a mount point _directory = path.replace("/","") # Strip all /. We should have something like this: devsda1. _mountpoint = os.path.join("/linstaller/mountpoints", _directory) if target: # Supersede _mountpoint with target _mountpoint = target if not os.path.exists(_mountpoint): os.makedirs(_mountpoint) # Create directory else: # Mountpoint already exists. See if it is mounted... if os.path.ismount(_mountpoint) and check: # Check if the _mountpoint is the place of the partition we want. infos = is_mounted(path) if not infos: # Not mounted. Here is mounted *another* partition raise m.CmdError("in %s there is mounted another partition!" % _mountpoint) # It is mounted. We can directly return this mountpoint. if opts: for opt in opts.split(","): if not opt in is_mounted(path)["options"]: # It is mounted, but the options are not here # Remount. m.sexec("mount -o %s,remount %s %s" % (opts, path, _mountpoint)) return _mountpoint # Check if the partition is already mounted on another mountpoint. if is_mounted(path) and check: # It is mounted. _mountpoint = is_mounted(path)["mountpoint"] if opts: for opt in opts.split(","): if not opt in is_mounted(path)["options"]: # It is mounted, but the options are not here # Remount. m.sexec("mount -o %s,remount %s %s" % (opts, path, _mountpoint)) return _mountpoint # Mount. Finally! if opts: opts = "-o %s" % opts else: opts = "" if typ: typ = "-t %s" % typ else: typ = "" m.sexec("mount %s %s %s %s" % (typ, opts, path, _mountpoint)) # Return mountpoint return _mountpoint