Examples

FAT and ext partition on GPT

 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
import logging
import os

import simplediskimage

logging.basicConfig(level=logging.DEBUG)

def main():
    image = simplediskimage.DiskImage("foo.img", partition_table='gpt')
    part_fat = image.new_partition("fat12", partition_flags=["BOOT"],
                                   partition_label="EFI System Partition")
    part_ext = image.new_partition("ext4", filesystem_label="hello")

    # Allocate some extra data on top of what's taken up by the data on the
    # ext partition
    part_ext.set_extra_bytes(16 * simplediskimage.SI.Mi)

    # Create two directories in the root of each partition
    part_fat.mkdir("fat1", "fat2")
    part_ext.mkdir("ext1", "ext2")

    # Copy the testdata dir into each partition in some interesting ways
    datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
    for part in (part_fat, part_ext):
        part.copy(os.path.join(datadir, "x"), os.path.join(datadir, "y"))
        part.mkdir("internet")
        part.copy(os.path.join(datadir, "internet/z"), destination="internet")
        part.copy(os.path.join(datadir, "internet/recursive_copy"), destination="internet")

    image.commit()
    print("sudo kpartx -av foo.img")
    print("...")
    print("sudo kpartx -dv foo.img")

if __name__ == '__main__':
    main()

Single bootable FAT partition, using sfdisk

 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
import logging

import simplediskimage

from common import generate_bb_testdata

logging.basicConfig(level=logging.DEBUG)

def main():
    # Generate test data
    generate_bb_testdata()

    # Create image
    image = simplediskimage.DiskImage("bar.img", partition_table='msdos',
                                      partitioner=simplediskimage.Sfdisk)
    part_fat = image.new_partition("fat16", partition_flags=["BOOT"])

    # Copy the files to the root, could also be written:
    # part_fat.copy("file1", "file2", destination="/"), or without destination
    part_fat.copy("generated/u-boot.img")
    part_fat.copy("generated/MLO")

    # Make sure that the partition is always 48 MiB
    part_fat.set_fixed_size_bytes(48 * simplediskimage.SI.Mi)

    image.commit()
    print("sudo kpartx -av bar.img")
    print("...")
    print("sudo kpartx -dv bar.img")

if __name__ == '__main__':
    main()

Using the NullPartitioner to create a raw image

 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
import logging
import os

import simplediskimage

logging.basicConfig(level=logging.DEBUG)

def main():
    image = simplediskimage.DiskImage("null-partitioner.ext4",
                                      partition_table='null',
                                      partitioner=simplediskimage.NullPartitioner)
    part = image.new_partition("ext4")

    # Allocate some extra data on top of what's taken up by the data on the
    # ext partition
    part.set_extra_bytes(2 * simplediskimage.SI.Mi)

    # Create two directories in the root of the partition
    part.mkdir("ext1", "ext2")

    # Copy some data from the testdata dir into the image
    datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
    part.copy(os.path.join(datadir, "x"), os.path.join(datadir, "y"))

    image.commit()
    print("sudo mount null-partitioner.ext4 /mnt")
    print("...")
    print("sudo umount /mnt")

if __name__ == '__main__':
    main()

Using a raw image as the filesystem for a partition

 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
import logging
import os

import simplediskimage

from common import generate_bb_testdata

logging.basicConfig(level=logging.DEBUG)

def main():
    ext4_source = "./null-partitioner.ext4"
    # Make sure the raw ext4 image has been created by running the
    # null-partitioner example
    if not os.path.exists(ext4_source):
        print("Run the null-partitioner.py example first")

    # Generate test data
    generate_bb_testdata()

    # Create image
    image = simplediskimage.DiskImage("raw-filesystem-on-p2.img",
                                      partition_table='msdos',
                                      partitioner=simplediskimage.Sfdisk)
    part_fat = image.new_partition("fat16", partition_flags=["BOOT"])
    part_ext = image.new_partition("ext4", raw_filesystem_image=True)

    # Copy the files to the root, could also be written:
    # part_fat.copy("file1", "file2", destination="/"), or without destination
    part_fat.copy("generated/u-boot.img")
    part_fat.copy("generated/MLO")

    # Make sure that the partition is always 48 MiB
    part_fat.set_fixed_size_bytes(48 * simplediskimage.SI.Mi)

    # Copy the ext image into the raw partition
    part_ext.copy(ext4_source)

    # The partition can be expanded beyond the size of the image, but beware
    # the warnings in the documentation before doing something like this!
    #part_ext.set_extra_bytes(16 * simplediskimage.SI.Mi)

    image.commit()
    print("sudo kpartx -av raw-filesystem-on-p2.img")
    print("...")
    print("sudo kpartx -dv raw-filesystem-on-p2.img")

if __name__ == '__main__':
    main()

Initialize a file system using a rootfs archive

 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
# This example might look a bit convoluted as we create an archive here just to
# extract it in the companion python script, but we are simulating a situation
# where a separate build system delivers a tar (might as well be a cpio
# archive), which the python script will unpack and use as the basis of a
# partition. There are multiple variants to this, for example:
#
# - The rootfs is delivered as a directory. In this case, the image creation
#   script might be run in the same fakeroot session, or the -s and -i
#   arguments to fakeroot may be used.
# - The rootfs is created using some python scripts under a fakeroot session.
#   If so, just add some calls to simplediskimage when the rootfs has been
#   created to turn it into an image.

TEMPDIR=./.rootfs-in-p2.tmp
EXAMPLE_USER=nobody
if ! id nobody &> /dev/null; then
  EXAMPLE_USER=$USER
fi

# Create rootfs.tar, this is usually done in a build system
rm -rf $TEMPDIR
mkdir $TEMPDIR
fakeroot <<EOF
set -e
cd $TEMPDIR
mkdir rootfs
mkdir -p rootfs/{root,dev,home/nobody}
echo data > rootfs/home/nobody/data
chown -R nobody:$(id -gn nobody) rootfs/home/nobody
mknod rootfs/dev/null c 1 3
dd if=/dev/urandom bs=1M count=16 of=rootfs/large_file
ln rootfs/large_file rootfs/large_file_link
tar -cf rootfs.tar -C rootfs .
EOF
rm -rf $TEMPDIR/rootfs

set -x
ls $TEMPDIR

# Invoke the example under fakeroot
fakeroot ./_rootfs-in-p2.py $TEMPDIR

rm -rf $TEMPDIR
 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import logging
import sys
import os
import tarfile

import simplediskimage

from common import generate_bb_testdata

logging.basicConfig(level=logging.DEBUG)

def main():
    # Check our surroundings, we should be:
    # - Getting the tempdir containing rootfs.tar as the sole argument
    # - Be executed inside a fakeroot environment
    if len(sys.argv) != 2 or "FAKEROOTKEY" not in os.environ:
        print("Don't run me directly, use rootfs-in-p2.sh")
        sys.exit(1)

    # Generate some testdata for the boot partition
    generate_bb_testdata()

    # Create image
    image = simplediskimage.DiskImage("rootfs-in-p2.img",
                                      partition_table='msdos',
                                      partitioner=simplediskimage.Sfdisk)
    part_fat = image.new_partition("fat16", partition_flags=["BOOT"])
    part_ext = image.new_partition("ext4", filesystem_label="root")

    # Copy files to the boot partition and set a fixed size
    part_fat.copy("generated/u-boot.img")
    part_fat.copy("generated/MLO")
    part_fat.set_fixed_size_bytes(48 * simplediskimage.SI.Mi)

    # Unpack the rootfs.tar file into a temporary directory
    temp_dir = sys.argv[1]
    rootfs_tar = os.path.join(temp_dir, "rootfs.tar")
    rootfs_dir = os.path.join(temp_dir, "p2-rootfs-dir")
    with tarfile.open(rootfs_tar, 'r:') as tf:
        def is_within_directory(directory, target):
            
            abs_directory = os.path.abspath(directory)
            abs_target = os.path.abspath(target)
        
            prefix = os.path.commonprefix([abs_directory, abs_target])
            
            return prefix == abs_directory
        
        def safe_extract(tar, path=".", members=None, *, numeric_owner=False):
        
            for member in tar.getmembers():
                member_path = os.path.join(path, member.name)
                if not is_within_directory(path, member_path):
                    raise Exception("Attempted Path Traversal in Tar File")
        
            tar.extractall(path, members, numeric_owner=numeric_owner) 
            
        
        safe_extract(tf, rootfs_dir)

    # Use the rootfs directory as the initial data directory for the second
    # partition (the rootfs)
    part_ext.set_initial_data_root(rootfs_dir)

    image.commit()
    print("sudo kpartx -av rootfs-in-p2.img")
    print("...")
    print("sudo kpartx -dv rootfs-in-p2.img")

if __name__ == '__main__':
    main()