summaryrefslogtreecommitdiffstats
path: root/tools/pyparted.py
blob: c51a13b77a28136ba338db4eae2cd7550c8eb997 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import logging
import parted  # type: ignore

from . import log

__all__ = ["list_partitions"]

L = logging.getLogger(__name__)

SUPPORTED_FS_TYPES = ["ext2", "ext3", "ext4", "xfs", "btrfs", "vfat", "ntfs"]


@log
def list_partitions(path):
    """Find all partitions with a filesystem or a LVM volume system in a RAW
    image file using `pyparted`.

    See also:
    https://github.com/dcantrell/pyparted

    Args:
        path (str): Path to the RAW image file.

    Returns:
        List of partitions. For example:
        [{'nr': 1, 'type': 'ext4', 'offset': 1048576, 'size': 1073741824},
         {'nr': 2, 'type': 'btrfs', 'offset': 1074790400, 'size': 20400046080}]
    """
    try:
        device = parted.getDevice(path)
    except Exception as e:
        L.error("failed to get device from %s: %r", path, e)
        return []

    try:
        disk = parted.Disk(device)
    except Exception as e:
        L.error("failed to read disk from %s: %r", path, e)
        return []

    ret = []
    for part in disk.partitions:
        if part.fileSystem and part.fileSystem.type in SUPPORTED_FS_TYPES:
            part_type = part.fileSystem.type
        elif part.getFlag(parted.PARTITION_LVM):
            part_type = "lvm"
        else:
            continue

        ret.append({
            "nr": part.number,
            "type": part_type,
            "offset": part.geometry.start * device.sectorSize,  # in bytes
            "size": part.geometry.length * device.sectorSize  # in bytes
        })

    return ret