def maybeCreateLabel(self):
        """Set up an msdos label."""

        self.partedDevice = parted.getDevice(self.device)
        try:
            self.partedDisk = parted.newDisk(self.partedDevice)
            if self.partedDisk.type == 'msdos':
                self.log.info("disk %s is already msdos", self.device)
                return 0
            self.log.warn("disk %s has wrong label %s",
                          self.device, self.partedDisk.type)
        except (DiskException, PartedException) as ex:
            self.log.error("cannot get partition table from %s: %s",
                           self.device, str(ex))
        except Exception:
            self.log.exception("cannot get partition table from %s",
                               self.device)

        self.log.info("clobbering disk label on %s", self.device)
        self.partedDevice.clobber()

        self.log.info("creating msdos label on %s", self.device)
        self.partedDisk = parted.freshDisk(self.partedDevice, 'msdos')

        return 0
예제 #2
0
    def maybeCreateLabel(self):
        """Set up an msdos label."""

        self.partedDevice = parted.getDevice(self.device)
        try:
            self.partedDisk = parted.newDisk(self.partedDevice)
            if self.partedDisk.type == 'msdos':
                self.log.info("disk %s is already msdos", self.device)
                return 0
            self.log.warn("disk %s has wrong label %s",
                          self.device, self.partedDisk.type)
        except (DiskException, PartedException) as ex:
            self.log.error("cannot get partition table from %s: %s",
                           self.device, str(ex))
        except Exception:
            self.log.exception("cannot get partition table from %s",
                               self.device)

        self.log.info("clobbering disk label on %s", self.device)
        self.partedDevice.clobber()

        self.log.info("creating msdos label on %s", self.device)
        self.partedDisk = parted.freshDisk(self.partedDevice, 'msdos')

        return 0
예제 #3
0
def _get_grubenv_entry(entry_name, device):
    try:
        # Try to mount the device's first partition
        disk = parted.newDisk(device)
        esp = disk.partitions[0]
        os.makedirs('/mnt/boot', exist_ok=True)
        subprocess.run(['mount', esp.path, '/mnt/boot'],
                       check=True,
                       stdout=subprocess.DEVNULL,
                       stderr=subprocess.DEVNULL)
        # Try to read entry from grubenv
        grub_list = subprocess.run(['grub-editenv', GRUB_ENV, 'list'],
                                   check=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.DEVNULL,
                                   universal_newlines=True)
        entry_match = re.search("^" + entry_name + "=(.+)$", grub_list.stdout,
                                re.MULTILINE)
        if entry_match == None:
            return None
        else:
            return entry_match.group(1)
    except:
        return None
    finally:
        subprocess.run(['umount', '/mnt/boot'],
                       stdout=subprocess.DEVNULL,
                       stderr=subprocess.DEVNULL)
예제 #4
0
    def getDevice(self, input):
        ''' A method which gets information about the specified device.'''
        # Grab the parted device
        device = parted.getDevice(input)

        # And return a disk instance
        return parted.newDisk(device), device
예제 #5
0
    def __init__ (self, conf, testMode=False):
        self.conf = conf
        self.testMode = testMode
        self.resinBootPartPath = getBootPartition(conf)
        self.currentResinRootPartPath = getRootPartition(conf)

        self.device = parted.getDevice(getRootDevice(conf))
        self.disk = parted.newDisk(self.device)
예제 #6
0
def get_partitions(diskpath):
    """ Return array of partition names for given disk """
    dev = parted.getDevice(diskpath)
    disk = parted.newDisk(dev)
    partitions = []
    for part in disk.partitions:
        (_, _, pname) = part.path.rsplit("/")
        partitions.append({"name": pname, "size": part.getLength() * dev.sectorSize})

    return partitions
예제 #7
0
def get_partitions(diskpath):
    """ Return array of partition names for given disk """
    dev = parted.getDevice(diskpath)
    disk = parted.newDisk(dev)
    partitions = []
    for part in disk.partitions:
        (_, _, pname) = part.path.rsplit("/")
        partitions.append({"name": pname, "size": part.getLength() * dev.sectorSize})

    return partitions
예제 #8
0
def testUSB():
    devices = [dev.path for dev in parted.getAllDevices()]
    print(devices)
    usb = parted.getDevice('/dev/sdb')
    print(usb)
    disk = parted.newDisk(usb)
    partitionsDesc = [(part.type, part.number) for part in disk.partitions]
    print(disk.partitions[0])
    # print(disk.partitions[1])
    print(partitionsDesc)
    print(disk.partitions[0].fileSystem.type)
예제 #9
0
    def __init__(self, devpath):
        # Supported commands and corresponding handlers

        try:
            self.device = parted.getDevice(devpath)
        except parted.IOException as e:
            raise RuntimeError(e.message)

        try:
            self.disk = parted.newDisk(self.device)
            if self.disk.type != 'msdos':
                raise RuntimeError('Only MBR partitions are supported')
        except parted.DiskException:
            self.create_empty()
예제 #10
0
def revertRepartition(device, partition, deltastart, deltaend, unit='MiB'):
    dev = parted.getDevice(device)
    disk = parted.newDisk(dev)
    targetPartition = disk.getPartitionByPath(device + partition)
    geometry = targetPartition.geometry
    geometry.start += parted.sizeToSectors(deltastart, unit, dev.sectorSize)
    geometry.end += parted.sizeToSectors(deltaend, unit, dev.sectorSize)
    disk.deletePartition(targetPartition)
    partition = parted.Partition(disk=disk,
                                 type=parted.PARTITION_NORMAL,
                                 geometry=geometry)
    disk.addPartition(partition=partition,
                      constraint=dev.optimalAlignedConstraint)
    disk.commit()
예제 #11
0
def partition(diskname, specs, force=False, check_mode=False):
    """
    Create requested partitions.
    Returns nr. of created partitions or 0 when the disk was already partitioned.
    """
    count = 0

    dev = parted.getDevice(diskname)
    try:
        disk = parted.newDisk(dev)
    except parted.DiskException:
        # unrecognizable format, treat as empty disk
        disk = None

    if disk and len(disk.partitions) > 0 and not force:
        print "skipping", diskname
        return 0

    # create new partition table, wiping all existing data
    disk = parted.freshDisk(dev, 'gpt')
    # calculate nr. of partitions of each size
    assign_space(dev.getSize(), specs)
    last_megabyte = 1
    for spec in specs:
        for _ in range(spec.count):
            # create the partition
            start = parted.sizeToSectors(last_megabyte, "MiB", dev.sectorSize)
            length = parted.sizeToSectors(spec.size, "MiB", dev.sectorSize)
            geo = parted.Geometry(device=dev, start=start, length=length)
            filesystem = parted.FileSystem(type='ext4', geometry=geo)
            part = parted.Partition(disk=disk,
                                    type=parted.PARTITION_NORMAL,
                                    fs=filesystem,
                                    geometry=geo)
            disk.addPartition(partition=part,
                              constraint=dev.optimalAlignedConstraint)
            last_megabyte += spec.size
            count += 1
    try:
        if not check_mode:
            disk.commit()
    except parted.IOException:
        # partitions have been written, but we have been unable to inform the
        # kernel of the change, probably because they are in use.
        # Ignore it and hope for the best...
        pass
    return count
예제 #12
0
def partition(diskname, specs, force=False, check_mode=False):
    """
    Create requested partitions.
    Returns nr. of created partitions or 0 when the disk was already partitioned.
    """
    count = 0

    dev = parted.getDevice(diskname)
    try:
        disk = parted.newDisk(dev)
    except parted.DiskException:
        # unrecognizable format, treat as empty disk
        disk = None

    if disk and len(disk.partitions) > 0 and not force:
        print "skipping", diskname
        return 0

    # create new partition table, wiping all existing data
    disk = parted.freshDisk(dev, 'gpt')
    # calculate nr. of partitions of each size
    assign_space(dev.getSize(), specs)
    last_megabyte = 1
    for spec in specs:
        for _ in range(spec.count):
            # create the partition
            start = parted.sizeToSectors(last_megabyte, "MiB", dev.sectorSize)
            length = parted.sizeToSectors(spec.size, "MiB", dev.sectorSize)
            geo = parted.Geometry(device=dev, start=start, length=length)
            filesystem = parted.FileSystem(type='ext4', geometry=geo)
            part = parted.Partition(
                disk=disk,
                type=parted.PARTITION_NORMAL,
                fs=filesystem,
                geometry=geo)
            disk.addPartition(partition=part, constraint=dev.optimalAlignedConstraint)
            last_megabyte += spec.size
            count += 1
    try:
        if not check_mode:
            disk.commit()
    except parted.IOException:
        # partitions have been written, but we have been unable to inform the
        # kernel of the change, probably because they are in use.
        # Ignore it and hope for the best...
        pass
    return count
예제 #13
0
파일: fdisk.py 프로젝트: sk8abraham/forense
def main():
    opt = opciones()
    verifica(opt)
    #Inicializando dispositivo
    try:
        print '\nVerificando dispositivo............',
        sdb = parted.getDevice(opt.device)
    except Exception:
        print '[ERROR]'
        exit(1)
    print '[OK]'
    print '\nDispositivo seleccionado: ' + opt.device
    c = ''
    while c != 'y':
        c = raw_input(
            '\nAl dispositivo ' + opt.device +
            ' se le eliminara la tabla de particion actual, quieres continuar? [Y/n] '
        )
        c = c.lower()
        if c == 'n':
            print '\nSaliendo ...\n'
            exit(1)
        elif c == '' or c == 'y':
            c = 'y'
            sdb.clobber()
            print ''
            pass
    try:
        disk = parted.newDisk(sdb)
    except Exception:
        pass
    print 'Creando dispositivo msdos\n'
    disk = parted.freshDisk(sdb, 'msdos')
    print 'Tipos aceptados'
    for x in parted.fileSystemType.keys():
        print x + ' ',
    print ''
    fin = 0
    n = raw_input('\nCuantas particiones van a ser? (maximo 4)> ')
    print ''
    for x in range(int(n)):
        print 'Particion primaria ' + str(x + 1) + ':'
        t = raw_input('Tipo> ')
        s = long(raw_input('Tamaño en MiB> '))
        print ''
        fin = particion_pri(sdb, disk, s, t, fin)
예제 #14
0
def capture(args):
    """Captures an image of args.src to args.dest, and shrinks the filesystem on the last partition"""
    # Get device info
    device = parted.getDevice(args.src)
    lastpart = parted.newDisk(device).partitions[-1]
    lastsector = lastpart.geometry.end + 1
    sectorsize = device.sectorSize
    lastbyte = lastsector * sectorsize

    logging.debug("Total Size: %s", str(lastbyte))

    if os.path.isfile(args.dest):
        if not yes_or_no("File: '%s' already exists. Overwrite?", args.dest):
            print("Operation aborted.")
            raise SystemExit

    if not args.no_shrink: lastbyte = shrinkfs(lastpart, args.free)

    if not args.no_copy:
        docopy(args.src, args.dest, lastbyte, args.buffer_size)
예제 #15
0
    def getDevice(self):
        devices = parted.getAllDevices()
        self.chosen_device = getDevice(devices)

        try:
            self.chosen_device = int(self.chosen_device) - 1
            if self.chosen_device < 0 or self.chosen_device > len(devices) - 1:
                self.valid = False
                self.code = 103
                self.message = "Invalid number: out of range"
                return
            device = devices[self.chosen_device].path
        except ValueError:
            if not path.exists(self.chosen_device):
                self.valid = False
                self.code = 101
                self.message = "Invalid file: file does not exist"
                return
            device = self.chosen_device

        self.device = parted.getDevice(device)
        self.disk = parted.newDisk(self.device)
        self.disk_file = open(self.device.path, "rb")
예제 #16
0
def extract_root_partition(image_filename, force=False):
    root_partition_image = '{}-root'.format(image_filename)
    if force or not os.path.isfile(root_partition_image):
        device = parted.getDevice(image_filename)
        sector_size = device.sectorSize
        disk = parted.newDisk(device)

        for partition in disk.partitions:
            filesystem = partition.fileSystem
            if filesystem.type == 'ext4':
                root_partition_start = partition.geometry.start * sector_size
                root_partition_size = partition.geometry.length * sector_size

        with open(image_filename, 'rb') as f:
            with open(root_partition_image, 'wb') as out:
                bytes_read = 0
                f.seek(root_partition_start)
                chunk = f.read(1024)
                while bytes_read < root_partition_size:
                    out.write(chunk)
                    chunk = f.read(1024)
                    bytes_read += 1024
    return root_partition_image
예제 #17
0
    def lookupPartitions(self, device_name):
        result = []
        try:
            dev = parted.getDevice(device_name)
            disk = parted.newDisk(dev)
            for p in disk.partitions:
                if p.fileSystem:
                    fs = {}
                    fs['filename'] = device_name
                    fs['number'] = p.number
                    fs['name'] = p.name
                    fs['type'] = p.fileSystem.type
                    fs['startBlock'] = p.fileSystem.geometry.start
                    fs['sectorsize'] = dev.sectorSize
                    fs['startOffset'] = dev.sectorSize * p.fileSystem.geometry.start
                    result.append(fs)
        except parted.DiskException as e:
            fs = {}
            fs['error'] = "DiskException"
            fs['desc'] = str(e)
            result.append(fs)
            #print('DiskException lookupPartitions exception: '+str(e))
        except parted.IOException as e:
            fs = {}
            fs['error'] = "file not found"
            fs['desc'] = str(e)
            result.append(fs)
        except Exception as e:
            fs = {}
            fs['error'] = "error"
            fs['desc'] = str(e)
            result.append(fs)
            #print(e)
            #print('lookupPartitions exception: '+str(e))

        return result
예제 #18
0
    def __init__(self, devpath):
        # Supported commands and corresponding handlers
        self.commands = {
            'a': self.toggle_bootable,
            'd': self.delete_partition,
            'm': self.print_menu,
            'n': self.add_partition,
            'o': self.create_empty,
            'p': self.print_partitions,
            'q': self.quit,
            'w': self.write
        }

        try:
            self.device = parted.getDevice(devpath)
        except parted.IOException as e:
            raise RuntimeError(e.message)

        try:
            self.disk = parted.newDisk(self.device)
            if self.disk.type != 'msdos':
                raise RuntimeError('Only MBR partitions are supported')
        except parted.DiskException:
            self.create_empty()
예제 #19
0
    def findGpt(self):
        self.blkidParts = BlkidParser(log=self.log.getChild("blkid"))

        deviceOrLabel = self.im.platformConf['grub']['device']
        if deviceOrLabel.startswith('/dev'):
            tgtDevice, tgtLabel = deviceOrLabel, None
        else:
            tgtDevice, tgtLabel = None, deviceOrLabel

        # enumerate labeled partitions to try to identify
        # the boot device
        for part in self.blkidParts:
            dev, partno = part.splitDev()
            if tgtLabel is not None and tgtLabel == part.label:
                if not len(partno):
                    self.log.error("cannot use whole disk")
                    return 1
                if self.device is None:
                    self.device = dev
                else:
                    self.log.error("found multiple devices: %s, %s",
                                   dev, self.device)
                    return 1
            elif tgtDevice is not None and tgtDevice == dev:
                if not len(partno):
                    self.log.error("cannot use whole disk")
                    return 1
                if self.device is None:
                    self.device = dev
                else:
                    self.log.error("found multiple devices: %s, %s",
                                   dev, self.device)
                    return 1
        if self.device is None:
            self.log.error("cannot find an install device")
            return 1

        if not self.isUEFI:
            code = self.assertUnmounted()
            if code: return code

        # optionally back up a config partition
        # if it's on the boot device
        for part in self.blkidParts:
            dev, partno = part.splitDev()
            if dev == self.device and part.label == 'ONL-CONFIG':
                self.backupConfig(part.device)

        self.partedDevice = parted.getDevice(self.device)
        self.partedDisk = parted.newDisk(self.partedDevice)

        # enumerate the partitions that will stay and go
        minpart = -1
        for part in self.partedDisk.partitions:

            if part.getFlag(parted.PARTITION_HIDDEN):
                minpart = max(minpart, part.number+1)
                continue

            # else, the partition should exist
            blkidParts = [x for x in self.blkidParts if x.device == part.path]
            if not blkidParts:
                self.log.warn("cannot identify partition %s", part)
                continue

            blkidPart = blkidParts[0]
            if not blkidPart.isOnieReserved(): continue

            # else, check the GPT label for reserved-ness
            if (part.name
                and ('GRUB' in part.name
                     or 'ONIE-BOOT' in part.name
                     or 'DIAG' in part.name)):
                minpart = max(minpart, part.number+1)

        if minpart < 0:
            self.log.error("cannot find an install partition")
            return 1
        self.minpart = minpart

        return 0
예제 #20
0
print the partitions in a device/file according to pyparted
"""

import parted

# adjust as needed, eg /dev/sdc..
device = "sdcard.img"

# A device is a "thing" with own properties (type, manufacturer etc) - its a
# high level abstraction that lets you just identify you have the right device
device = parted.getDevice(device)

# grab a "disk" instance - the other choice is `freshDisk`, wheras `newDisk`
# seems to just read an existing disk (which is what we want for adding new
# partition)
disk = parted.newDisk(device)

print("***** sanity check *****")
print(f"result: {disk.check()}")

print("===== device ====")
print(f"  model: {device.model}")
print(f"  path: {device.path}")
print(f"  sectorSize: {device.sectorSize}")
print(f"  physicalSectorSize: {device.physicalSectorSize}")
print(f"  length: {device.length}")
# this next line can crash if you have a wonky GPT...
# print(f"  size (MB): {device.getSize()}")

print("===== disk ====")
print(f"  type: {disk.type}")
    def findGpt(self):
        self.blkidParts = BlkidParser(log=self.log.getChild("blkid"))

        deviceOrLabel = self.im.platformConf['grub']['device']
        if deviceOrLabel.startswith('/dev'):
            tgtDevice, tgtLabel = deviceOrLabel, None
        else:
            tgtDevice, tgtLabel = None, deviceOrLabel

        # enumerate labeled partitions to try to identify
        # the boot device
        for part in self.blkidParts:
            dev, partno = part.splitDev()
            if tgtLabel is not None and tgtLabel == part.label:
                if not len(partno):
                    self.log.error("cannot use whole disk")
                    return 1
                if self.device is None:
                    self.device = dev
                else:
                    self.log.error("found multiple devices: %s, %s",
                                   dev, self.device)
                    return 1
            elif tgtDevice is not None and tgtDevice == dev:
                if not len(partno):
                    self.log.error("cannot use whole disk")
                    return 1
                if self.device is None:
                    self.device = dev
                else:
                    self.log.error("found multiple devices: %s, %s",
                                   dev, self.device)
                    return 1
        if self.device is None:
            self.log.error("cannot find an install device")
            return 1

        code = self.assertUnmounted()
        if code: return code

        # optionally back up a config partition
        # if it's on the boot device
        for part in self.blkidParts:
            dev, partno = part.splitDev()
            if dev == self.device and part.label == 'ONL-CONFIG':
                self.backupConfig(part.device)

        self.partedDevice = parted.getDevice(self.device)
        self.partedDisk = parted.newDisk(self.partedDevice)

        # enumerate the partitions that will stay and go
        minpart = -1
        for part in self.partedDisk.partitions:

            if part.getFlag(parted.PARTITION_HIDDEN):
                minpart = max(minpart, part.number+1)
                continue

            # else, the partition should exist
            blkidParts = [x for x in self.blkidParts if x.device == part.path]
            if not blkidParts:
                self.log.warn("cannot identify partition %s", part)
                continue

            blkidPart = blkidParts[0]
            if not blkidPart.isOnieReserved(): continue

            # else, check the GPT label for reserved-ness
            if (part.name
                and ('GRUB' in part.name
                     or 'ONIE-BOOT' in part.name
                     or 'DIAG' in part.name)):
                minpart = max(minpart, part.number+1)

        if minpart < 0:
            self.log.error("cannot find an install partition")
            return 1
        self.minpart = minpart

        return 0
    def enter(self):
        if not self.should_enter():
            return

        self.context.logger.log("Entering split_root_partition state")

        device = parted.getDevice('/dev/sda')
        disk = parted.newDisk(device)

        original_root_fs_size = self._get_root_fs_size_in(device.sectorSize)
        self.context.logger.log(
            "Original root filesystem size (sectors): {0}".format(
                original_root_fs_size))

        desired_boot_partition_size = parted.sizeToSectors(
            256, 'MiB', device.sectorSize)
        self.context.logger.log(
            "Desired boot partition size (sectors): {0}".format(
                desired_boot_partition_size))

        desired_root_fs_size = original_root_fs_size - desired_boot_partition_size
        self.context.logger.log(
            "Desired root filesystem size (sectors): {0}".format(
                desired_root_fs_size))

        self.command_executor.Execute(
            "resize2fs /dev/sda1 {0}s".format(desired_root_fs_size), True)

        resized_root_fs_size = self._get_root_fs_size_in(device.sectorSize)

        self.context.logger.log(
            "Resized root filesystem size (sectors): {0}".format(
                resized_root_fs_size))

        if not desired_root_fs_size == resized_root_fs_size:
            raise Exception(
                "resize2fs failed, desired: {0}, resized: {1}".format(
                    desired_root_fs_size, resized_root_fs_size))

        self.context.logger.log("Root filesystem resized successfully")

        root_partition = disk.partitions[0]

        original_root_partition_start = root_partition.geometry.start
        original_root_partition_end = root_partition.geometry.end

        self.context.logger.log(
            "Original root partition start (sectors): {0}".format(
                original_root_partition_start))
        self.context.logger.log(
            "Original root partition end (sectors): {0}".format(
                original_root_partition_end))

        desired_root_partition_start = original_root_partition_start
        desired_root_partition_end = original_root_partition_end - desired_boot_partition_size
        desired_root_partition_size = desired_root_partition_end - desired_root_partition_start

        self.context.logger.log(
            "Desired root partition start (sectors): {0}".format(
                desired_root_partition_start))
        self.context.logger.log(
            "Desired root partition end (sectors): {0}".format(
                desired_root_partition_end))
        self.context.logger.log(
            "Desired root partition size (sectors): {0}".format(
                desired_root_partition_size))

        desired_root_partition_geometry = parted.Geometry(
            device=device,
            start=desired_root_partition_start,
            length=desired_root_partition_size)
        root_partition_constraint = parted.Constraint(
            exactGeom=desired_root_partition_geometry)
        disk.setPartitionGeometry(partition=root_partition,
                                  constraint=root_partition_constraint,
                                  start=desired_root_partition_start,
                                  end=desired_root_partition_end)

        desired_boot_partition_start = disk.getFreeSpaceRegions()[1].start
        desired_boot_partition_end = disk.getFreeSpaceRegions()[1].end
        desired_boot_partition_size = disk.getFreeSpaceRegions()[1].length

        self.context.logger.log(
            "Desired boot partition start (sectors): {0}".format(
                desired_boot_partition_start))
        self.context.logger.log(
            "Desired boot partition end (sectors): {0}".format(
                desired_boot_partition_end))

        desired_boot_partition_geometry = parted.Geometry(
            device=device,
            start=desired_boot_partition_start,
            length=desired_boot_partition_size)
        boot_partition_constraint = parted.Constraint(
            exactGeom=desired_boot_partition_geometry)
        desired_boot_partition = parted.Partition(
            disk=disk,
            type=parted.PARTITION_NORMAL,
            geometry=desired_boot_partition_geometry)

        disk.addPartition(partition=desired_boot_partition,
                          constraint=boot_partition_constraint)

        disk.commit()

        probed_root_fs = parted.probeFileSystem(disk.partitions[0].geometry)
        if not probed_root_fs == 'ext4':
            raise Exception("Probed root fs is not ext4")

        disk.partitions[1].setFlag(parted.PARTITION_BOOT)

        disk.commit()

        self.command_executor.Execute("partprobe", True)
        self.command_executor.Execute("mkfs.ext2 /dev/sda2", True)

        boot_partition_uuid = self._get_uuid("/dev/sda2")

        # Move stuff from /oldroot/boot to new partition, make new partition mountable at the same spot
        self.command_executor.Execute("mount /dev/sda1 /oldroot", True)
        self.command_executor.Execute("mkdir /oldroot/memroot", True)
        self.command_executor.Execute("mount --make-rprivate /", True)
        self.command_executor.Execute("pivot_root /oldroot /oldroot/memroot",
                                      True)
        self.command_executor.ExecuteInBash(
            "for i in dev proc sys; do mount --move /memroot/$i /$i; done",
            True)
        self.command_executor.Execute("mv /boot /boot.backup", True)
        self.command_executor.Execute("mkdir /boot", True)
        self._append_boot_partition_uuid_to_fstab(boot_partition_uuid)
        self.command_executor.Execute("cp /etc/fstab /memroot/etc/fstab", True)
        self.command_executor.Execute("mount /boot", True)
        self.command_executor.ExecuteInBash("mv /boot.backup/* /boot/", True)
        self.command_executor.Execute("rmdir /boot.backup", True)
        self.command_executor.Execute("mount --make-rprivate /", True)
        self.command_executor.Execute("pivot_root /memroot /memroot/oldroot",
                                      True)
        self.command_executor.Execute("rmdir /oldroot/memroot", True)
        self.command_executor.ExecuteInBash(
            "for i in dev proc sys; do mount --move /oldroot/$i /$i; done",
            True)
        self.command_executor.Execute("systemctl restart rsyslog", True)
        self.command_executor.Execute("systemctl restart systemd-udevd", True)
        self.command_executor.Execute("systemctl restart walinuxagent", True)
        self.command_executor.Execute("umount /oldroot/boot", True)
        self.command_executor.Execute("umount /oldroot", True)
예제 #23
0
파일: parted.py 프로젝트: ryan-blakley/pbr
def get_part_layout(udev_ctx):
    """
    Loop through the disk and use parted and udev to capture the
    partition layout. Might need to add threading to the for loop in the
    future for servers with a ton of disk.
    :return:
    """
    from glob import glob
    from re import search

    # Define dict to store disk info.
    disks_dict = dict()

    def update(name, p_dev):
        if name:
            disks_dict.update({name: disk})
        else:
            disks_dict.update({d.device_node: disk})

        p_dev.removeFromCache()

    # Loop through disk pulled from udev.
    for d in udev_ctx.list_devices(subsystem='block', DEVTYPE='disk'):
        dm_name = None

        # Skip if the device is a /dev/loop, mdraid, cd, or usb.
        if (not search("/dev/loop", d.device_node)
                and not d.get('MD_NAME', False)
                and not search("cd", d.get('ID_TYPE', ""))
                and not search("usb", d.get('ID_BUS', ""))
                and not int(d.get('DM_MULTIPATH_DEVICE_PATH', False))):

            # If it's a dm device check if it's mpath if not skip it,
            # if it is set the dm_name.
            if search("dm-", d.device_node):
                if search("^mpath-", d.get('DM_UUID', "")):
                    dm_name = f"/dev/mapper/{d.get('DM_NAME')}"
                else:
                    continue

            # If the device is an mpath path, then skip it, would prefer
            # to query udev here, but apparently in the recovery
            # environment the DM_MULTIPATH_DEVICE_PATH variable is always
            # a zero for some reason. So I don't trust using it, so check
            # if the dev has any holders, and if they're an mpath device.
            holders = glob(
                f"/sys/block/{d.device_node.split('/')[-1]}/holders/*/dm/uuid")
            if holders:
                with open(holders[0]) as f:
                    if f.readline().split()[0].startswith("mpath-"):
                        continue

            # Define a dict to store each disk info.
            disk = dict()

            # Fetch the parted device.
            p_device = parted.getDevice(d.device_node)

            # Add parted info, and udev info to the dict.
            disk.update({
                "id_serial": d.get('ID_SERIAL_SHORT'),
                "id_wwn": d.get('ID_WWN'),
                "id_path": d.get('ID_PATH'),
                "size": p_device.length
            })

            # Add a catch for disk that don't have a label and skip them.
            try:
                # Fetch the parted disk object.
                p_disk = parted.newDisk(p_device)
            except (DeviceException, DiskException):
                disk.update({
                    "fs_type": d.get('ID_FS_TYPE'),
                    "fs_uuid": d.get('ID_FS_UUID', '')
                })
                update(dm_name, p_device)
                continue

            # Add parted info, and udev info to the dict.
            disk.update({"type": p_disk.type})

            if p_disk.type == "loop":
                disk.update({
                    "fs_type": d.get('ID_FS_TYPE'),
                    "fs_uuid": d.get('ID_FS_UUID', '')
                })
                update(dm_name, p_device)
                continue

            # Loop through the partitions, and grab info.
            for p in p_disk.partitions:
                # Define dict to store partition info.
                part = dict()

                # Grab any part flags, and the part type.
                part.update({"flags": p.getFlagsAsString(), "type": p.type})

                # If the disk label isn't msdos, check for part names.
                if "msdos" not in p_disk.type:
                    try:
                        if p.name:
                            part.update({"name": p.name})
                        else:
                            part.update({"name": None})
                    except PartitionException:
                        part.update({"name": None})
                        pass
                else:
                    part.update({"name": None})

                # Pull the fs type from udev instead of parted.
                if dm_name and dm_name[-1].isnumeric():
                    dev = f"{dm_name}p{p.number}"
                elif dm_name:
                    dev = f"{dm_name}{p.number}"
                elif d.device_node[-1].isnumeric():
                    dev = f"{d.device_node}p{p.number}"
                else:
                    dev = f"{d.device_node}{p.number}"

                if is_block(dev):
                    part_info = dev_from_file(udev_ctx, dev)

                    # Add the fs info, and the geometry info.
                    part.update({
                        "fs_type": part_info.get('ID_FS_TYPE', ''),
                        "fs_uuid": part_info.get('ID_FS_UUID', ''),
                        "fs_label": part_info.get('ID_FS_LABEL', ''),
                        "start": p.geometry.start,
                        "end": p.geometry.end
                    })

                # Add the part dict as an entry to the disk dict.
                # Might change this to the full path later, for
                # now just the part number.
                disk.update({p.number: part})

            # Add the disk dict as an entry to the master dict.
            update(dm_name, p_device)

    return disks_dict
    def enter(self):
        if not self.should_enter():
            return

        self.context.logger.log("Entering split_root_partition state")

        device = parted.getDevice(self.rootfs_disk)
        disk = parted.newDisk(device)

        original_root_fs_size = self._get_root_fs_size_in(device.sectorSize)
        self.context.logger.log("Original root filesystem size (sectors): {0}".format(original_root_fs_size))

        desired_boot_partition_size = parted.sizeToSectors(256, 'MiB', device.sectorSize)
        self.context.logger.log("Desired boot partition size (sectors): {0}".format(desired_boot_partition_size))

        desired_root_fs_size = int(original_root_fs_size - desired_boot_partition_size)
        self.context.logger.log("Desired root filesystem size (sectors): {0}".format(desired_root_fs_size))

        attempt = 1
        while attempt < 10:
            resize_result = self.command_executor.Execute("resize2fs {0} {1}s".format(self.rootfs_block_device, desired_root_fs_size))

            if resize_result == 0:
                break
            else:
                self.command_executor.Execute('systemctl restart systemd-udevd')
                self.command_executor.Execute('systemctl restart systemd-timesyncd')
                self.command_executor.Execute('udevadm trigger')

                sleep(10)

                attempt += 1

        resized_root_fs_size = self._get_root_fs_size_in(device.sectorSize)

        self.context.logger.log("Resized root filesystem size (sectors): {0}".format(resized_root_fs_size))

        if not desired_root_fs_size == resized_root_fs_size:
            raise Exception("resize2fs failed, desired: {0}, resized: {1}".format(desired_root_fs_size,
                                                                                  resized_root_fs_size))

        self.context.logger.log("Root filesystem resized successfully")

        root_partition = disk.getPartitionByPath(os.path.realpath(self.rootfs_block_device))

        original_root_partition_start = root_partition.geometry.start
        original_root_partition_end = root_partition.geometry.end

        self.context.logger.log("Original root partition start (sectors): {0}".format(original_root_partition_start))
        self.context.logger.log("Original root partition end (sectors): {0}".format(original_root_partition_end))

        desired_root_partition_start = original_root_partition_start
        desired_root_partition_end = original_root_partition_end - desired_boot_partition_size
        desired_root_partition_size = desired_root_partition_end - desired_root_partition_start

        self.context.logger.log("Desired root partition start (sectors): {0}".format(desired_root_partition_start))
        self.context.logger.log("Desired root partition end (sectors): {0}".format(desired_root_partition_end))
        self.context.logger.log("Desired root partition size (sectors): {0}".format(desired_root_partition_size))

        desired_root_partition_geometry = parted.Geometry(device=device,
                                                          start=desired_root_partition_start,
                                                          length=desired_root_partition_size)
        root_partition_constraint = parted.Constraint(exactGeom=desired_root_partition_geometry)
        disk.setPartitionGeometry(partition=root_partition,
                                  constraint=root_partition_constraint,
                                  start=desired_root_partition_start,
                                  end=desired_root_partition_end)

        desired_boot_partition_start = disk.getFreeSpaceRegions()[1].start
        desired_boot_partition_end = disk.getFreeSpaceRegions()[1].end
        desired_boot_partition_size = disk.getFreeSpaceRegions()[1].length

        self.context.logger.log("Desired boot partition start (sectors): {0}".format(desired_boot_partition_start))
        self.context.logger.log("Desired boot partition end (sectors): {0}".format(desired_boot_partition_end))

        desired_boot_partition_geometry = parted.Geometry(device=device,
                                                          start=desired_boot_partition_start,
                                                          length=desired_boot_partition_size)
        boot_partition_constraint = parted.Constraint(exactGeom=desired_boot_partition_geometry)
        desired_boot_partition = parted.Partition(disk=disk,
                                                  type=parted.PARTITION_NORMAL,
                                                  geometry=desired_boot_partition_geometry)

        if (root_partition.getFlag(parted.PARTITION_BOOT)):
            desired_boot_partition.setFlag(parted.PARTITION_BOOT)

        disk.addPartition(partition=desired_boot_partition, constraint=boot_partition_constraint)

        disk.commit()

        probed_root_fs = parted.probeFileSystem(desired_root_partition_geometry)
        if not probed_root_fs == 'ext4':
            raise Exception("Probed root fs is not ext4")

        self.command_executor.Execute("partprobe", True)
        self.command_executor.Execute("mkfs.ext2 {0}".format(self.bootfs_block_device), True)

        boot_partition_uuid = self._get_uuid(self.bootfs_block_device)

        # Move stuff from /oldroot/boot to new partition, make new partition mountable at the same spot
        self.command_executor.Execute("mount {0} /oldroot".format(self.rootfs_block_device), True)
        self.command_executor.Execute("mkdir -p /boot", True)
        self.command_executor.Execute("cp /oldroot/etc/fstab /etc/fstab", True)
        self._append_boot_partition_uuid_to_fstab(boot_partition_uuid)
        self.command_executor.Execute("cp /etc/fstab /oldroot/etc/fstab", True)
        self.command_executor.Execute("mount /boot", True)
        self.command_executor.ExecuteInBash("mv /oldroot/boot/* /boot/", True)
        self.command_executor.Execute("umount /boot", True)
        self.command_executor.Execute("umount /oldroot", True)
예제 #25
0
파일: sd.py 프로젝트: himblick/himblick
    def partition(self, dev: Dict[str, Any]):
        """
        Update partitioning on the SD card
        """
        try:
            import parted
        except ModuleNotFoundError:
            raise Fail("please install python3-parted")

        # See https://github.com/dcantrell/pyparted/tree/master/examples
        # for pyparted examples
        # See https://www.gnu.org/software/parted/api/modules.html
        # for library documentation
        # See http://www.linuxvoice.com/issues/005/pyparted.pdf
        # for more exmaples and in-depth explanations

        device = parted.getDevice(dev["path"])
        disk = parted.newDisk(device)

        if not disk.check():
            raise Fail("Parted disk check failed (TODO: find out how to get details about what check failed)")

        partitions = list(disk.partitions)
        if len(partitions) > 3:
            raise Fail(f"SD card has too many ({len(partitions)}) partitions: reset it with --write-image")

        part_boot = partitions[0]
        fs = part_boot.fileSystem
        if not fs:
            raise Fail("SD boot partition has no file system: reset it with --write-image")
        if fs.type != "fat32":
            raise Fail("SD boot partition is not a fat32 partition: reset it with --write-image")

        part_root = partitions[1]
        fs = part_root.fileSystem
        if not fs:
            raise Fail("SD system partition has no file system: reset it with --write-image")
        if fs.type != "ext4":
            raise Fail("SD system partition is not an ext4 partition: reset it with --write-image")

        if len(partitions) == 3:
            part_media = partitions[2]
        else:
            part_media = None

        # TODO: check partition label, and error out if it exists and is not 'media'

        target_root_size = int(round(4 * 1024**3 / device.sectorSize))
        need_root_resize = part_root.geometry.end - part_root.geometry.start < target_root_size - 16
        if need_root_resize:
            log.info("%s: partition is only %.1fGB and needs resizing (current: %d, target: %d)",
                     part_root.path, target_root_size * device.sectorSize / 1024**3,
                     part_root.geometry.end - part_root.geometry.start, target_root_size)

            if part_media:
                log.info("%s: partition needs resize: removing media partition %s", part_root.path, part_media.path)
                disk.deletePartition(part_media)
                part_media = None

            # Resize rootfs partition
            constraint = device.optimalAlignedConstraint
            constraint.minSize = target_root_size
            constraint.maxSize = target_root_size
            disk.maximizePartition(part_root, constraint)
            disk.commit()
            time.sleep(0.5)
            self.umount(self.locate())
            time.sleep(0.3)

            run(["e2fsck", "-fy", part_root.path])
            run(["resize2fs", part_root.path])

        if part_media is None:
            # Get the last free space
            free_space = disk.getFreeSpaceRegions()[-1]

            # Create media partition
            partition = parted.Partition(
                    disk=disk,
                    type=parted.PARTITION_NORMAL,
                    geometry=free_space)
            disk.addPartition(partition=partition, constraint=device.optimalAlignedConstraint)
            disk.commit()
            time.sleep(0.5)
            self.umount(self.locate())
            time.sleep(0.3)
            log.info("%s media partition created", format_gb(free_space.length * device.sectorSize))

            # Create exFAT file system
            run(["mkexfatfs", "-n", "media", partition.path])
            log.info("%s media partition formatted", format_gb(free_space.length * device.sectorSize))
        else:
            # Current parted cannot seem to deal with exfat, let's use exfatfsck instead
            res = run(["exfatfsck", "-n", partitions[2].path], capture_output=True)
            if res.returncode != 0:
                raise Fail("SD media partition exFAT file system failed checks:"
                           " reset it with --write-image and rerun --partition")
    def enter(self):
        if not self.should_enter():
            return

        self.context.logger.log("Entering split_root_partition state")

        device = parted.getDevice('/dev/sda')
        disk = parted.newDisk(device)

        original_root_fs_size = self._get_root_fs_size_in(device.sectorSize)
        self.context.logger.log("Original root filesystem size (sectors): {0}".format(original_root_fs_size))

        desired_boot_partition_size = parted.sizeToSectors(256, 'MiB', device.sectorSize)
        self.context.logger.log("Desired boot partition size (sectors): {0}".format(desired_boot_partition_size))
      
        desired_root_fs_size = original_root_fs_size - desired_boot_partition_size
        self.context.logger.log("Desired root filesystem size (sectors): {0}".format(desired_root_fs_size))

        self.command_executor.Execute("resize2fs /dev/sda1 {0}s".format(desired_root_fs_size), True)

        resized_root_fs_size = self._get_root_fs_size_in(device.sectorSize)

        self.context.logger.log("Resized root filesystem size (sectors): {0}".format(resized_root_fs_size))

        if not desired_root_fs_size == resized_root_fs_size:
            raise Exception("resize2fs failed, desired: {0}, resized: {1}".format(desired_root_fs_size,
                                                                                  resized_root_fs_size))

        self.context.logger.log("Root filesystem resized successfully")

        root_partition = disk.partitions[0]

        original_root_partition_start = root_partition.geometry.start
        original_root_partition_end = root_partition.geometry.end

        self.context.logger.log("Original root partition start (sectors): {0}".format(original_root_partition_start))
        self.context.logger.log("Original root partition end (sectors): {0}".format(original_root_partition_end))

        desired_root_partition_start = original_root_partition_start
        desired_root_partition_end = original_root_partition_end - desired_boot_partition_size
        desired_root_partition_size = desired_root_partition_end - desired_root_partition_start

        self.context.logger.log("Desired root partition start (sectors): {0}".format(desired_root_partition_start))
        self.context.logger.log("Desired root partition end (sectors): {0}".format(desired_root_partition_end))
        self.context.logger.log("Desired root partition size (sectors): {0}".format(desired_root_partition_size))

        desired_root_partition_geometry = parted.Geometry(device=device,
                                                          start=desired_root_partition_start,
                                                          length=desired_root_partition_size)
        root_partition_constraint = parted.Constraint(exactGeom=desired_root_partition_geometry)
        disk.setPartitionGeometry(partition=root_partition,
                                  constraint=root_partition_constraint,
                                  start=desired_root_partition_start,
                                  end=desired_root_partition_end)

        desired_boot_partition_start = disk.getFreeSpaceRegions()[1].start
        desired_boot_partition_end = disk.getFreeSpaceRegions()[1].end
        desired_boot_partition_size = disk.getFreeSpaceRegions()[1].length

        self.context.logger.log("Desired boot partition start (sectors): {0}".format(desired_boot_partition_start))
        self.context.logger.log("Desired boot partition end (sectors): {0}".format(desired_boot_partition_end))

        desired_boot_partition_geometry = parted.Geometry(device=device,
                                                          start=desired_boot_partition_start,
                                                          length=desired_boot_partition_size)
        boot_partition_constraint = parted.Constraint(exactGeom=desired_boot_partition_geometry)
        desired_boot_partition = parted.Partition(disk=disk,
                                                  type=parted.PARTITION_NORMAL,
                                                  geometry=desired_boot_partition_geometry)

        disk.addPartition(partition=desired_boot_partition, constraint=boot_partition_constraint)

        disk.commit()

        probed_root_fs = parted.probeFileSystem(disk.partitions[0].geometry)
        if not probed_root_fs == 'ext4':
            raise Exception("Probed root fs is not ext4")

        disk.partitions[1].setFlag(parted.PARTITION_BOOT)

        disk.commit()
        
        self.command_executor.Execute("partprobe", True)
        self.command_executor.Execute("mkfs.ext2 /dev/sda2", True)
        
        boot_partition_uuid = self._get_uuid("/dev/sda2")

        # Move stuff from /oldroot/boot to new partition, make new partition mountable at the same spot
        self.command_executor.Execute("mount /dev/sda1 /oldroot", True)
        self.command_executor.Execute("mkdir /oldroot/memroot", True)
        self.command_executor.Execute("mount --make-rprivate /", True)
        self.command_executor.Execute("pivot_root /oldroot /oldroot/memroot", True)
        self.command_executor.ExecuteInBash("for i in dev proc sys; do mount --move /memroot/$i /$i; done", True)
        self.command_executor.Execute("mv /boot /boot.backup", True)
        self.command_executor.Execute("mkdir /boot", True)
        self._append_boot_partition_uuid_to_fstab(boot_partition_uuid)
        self.command_executor.Execute("cp /etc/fstab /memroot/etc/fstab", True)
        self.command_executor.Execute("mount /boot", True)
        self.command_executor.ExecuteInBash("mv /boot.backup/* /boot/", True)
        self.command_executor.Execute("rmdir /boot.backup", True)
        self.command_executor.Execute("mount --make-rprivate /", True)
        self.command_executor.Execute("pivot_root /memroot /memroot/oldroot", True)
        self.command_executor.Execute("rmdir /oldroot/memroot", True)
        self.command_executor.ExecuteInBash("for i in dev proc sys; do mount --move /oldroot/$i /$i; done", True)
        self.command_executor.Execute("systemctl restart rsyslog", True)
        self.command_executor.Execute("systemctl restart systemd-udevd", True)
        self.command_executor.Execute("systemctl restart walinuxagent", True)
        self.command_executor.Execute("umount /oldroot/boot", True)
        self.command_executor.Execute("umount /oldroot", True)