1#!/usr/bin/env python
2
3# Copyright (C) 2018-2022 Intel Corporation.
4# SPDX-License-Identifier: BSD-3-Clause
5
6import ConfigParser
7import uuid
8import struct
9import sys
10
11type_2_guid = {
12# official guid for gpt partition type
13    'fat' : 'ebd0a0a2-b9e5-4433-87c0-68b6b72699c7',
14    'esp' : 'c12a7328-f81f-11d2-ba4b-00a0c93ec93b',
15    'linux' : '0fc63daf-8483-4772-8e79-3d69d8477de4',
16    'linux-swap' : '0657fd6d-a4ab-43c4-84e5-0933c84b4f4f',
17# generated guid for android
18    'boot' : '49a4d17f-93a3-45c1-a0de-f50b2ebe2599',
19    'recovery' : '4177c722-9e92-4aab-8644-43502bfd5506',
20    'misc' : 'ef32a33b-a409-486c-9141-9ffb711f6266',
21    'metadata' : '20ac26be-20b7-11e3-84c5-6cfdb94711e9',
22    'tertiary' : '767941d0-2085-11e3-ad3b-6cfdb94711e9',
23    'factory' : '9fdaa6ef-4b3f-40d2-ba8d-bff16bfb887b' }
24
25def zero_pad(s, size):
26    if (len(s) > size):
27        print 'error', len(s)
28    s += '\0' * (size - len(s))
29    return s
30
31def copy_section(cfg, a, b):
32    cfg.add_section(b)
33    for option in cfg.options(a):
34        cfg.set(b, option, cfg.get(a, option))
35
36def preparse_slots(cfg, partitions):
37    if not cfg.has_option('base', 'nb_slot'):
38        return partitions
39
40    nb_slot = cfg.getint('base', 'nb_slot')
41
42    parts_with_slot = []
43    for p in partitions:
44        section = "partition." + p
45        if cfg.has_option(section, 'has_slot'):
46            for i in range(ord('a'), ord('a') + nb_slot):
47                suffix = "_%c" % i
48                new_part = p + suffix
49                new_section = "partition." + new_part
50
51                copy_section(cfg, section, new_section)
52                cfg.set(new_section, 'label', cfg.get(section, 'label') + suffix)
53                parts_with_slot.append(new_part);
54        else:
55            parts_with_slot.append(p);
56
57    return parts_with_slot
58
59def preparse_partitions(gpt_in, cfg):
60    with open(gpt_in, 'r') as f:
61        data = f.read()
62
63    partitions = cfg.get('base', 'partitions').split()
64
65    for l in data.split('\n'):
66        words = l.split()
67        if len(words) > 2:
68            if words[0] == 'partitions' and words[1] == '+=':
69                partitions += words[2:]
70
71    return partitions
72
73def main():
74    if len(sys.argv) != 2:
75        print 'Usage : ', sys.argv[0], 'gpt_in1.ini'
76        print '    write binary to stdout'
77        sys.exit(1)
78
79    gpt_in = sys.argv[1]
80
81    cfg = ConfigParser.SafeConfigParser()
82
83    cfg.read(gpt_in)
84
85    part = preparse_partitions(gpt_in, cfg)
86    part = preparse_slots(cfg, part)
87
88    magic = 0x6a8b0da1
89    start_lba = 0
90    if cfg.has_option('base', 'start_lba'):
91        start_lba = cfg.getint('base', 'start_lba')
92    npart = len(part)
93
94    out = sys.stdout
95    out.write(struct.pack('<I', magic))
96    out.write(struct.pack('<I', start_lba))
97    out.write(struct.pack('<I', npart))
98    for p in part:
99        length = cfg.get('partition.' + p, 'len')
100        out.write(struct.pack('<i', int(length)))
101
102        label = cfg.get('partition.' + p, 'label').encode('utf-16le')
103        out.write(zero_pad(label, 36 * 2))
104
105        guid_type = cfg.get('partition.' + p, 'type')
106        guid_type = uuid.UUID(type_2_guid[guid_type])
107        out.write(guid_type.bytes_le)
108
109        guid = uuid.uuid4()
110        out.write(guid.bytes_le)
111
112if __name__ == "__main__":
113    main()
114