diff options
Diffstat (limited to 'scripts/lib/wic/utils')
-rw-r--r-- | scripts/lib/wic/utils/partitionedfs.py | 301 |
1 files changed, 0 insertions, 301 deletions
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py deleted file mode 100644 index cdf8f08015..0000000000 --- a/scripts/lib/wic/utils/partitionedfs.py +++ /dev/null | |||
@@ -1,301 +0,0 @@ | |||
1 | #!/usr/bin/env python -tt | ||
2 | # | ||
3 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
4 | # Copyright (c) 2007, 2008 Red Hat, Inc. | ||
5 | # Copyright (c) 2008 Daniel P. Berrange | ||
6 | # Copyright (c) 2008 David P. Huff | ||
7 | # | ||
8 | # This program is free software; you can redistribute it and/or modify it | ||
9 | # under the terms of the GNU General Public License as published by the Free | ||
10 | # Software Foundation; version 2 of the License | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, but | ||
13 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
15 | # for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License along | ||
18 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
19 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | |||
21 | import os | ||
22 | |||
23 | from wic import msger | ||
24 | from wic.utils.errors import ImageError | ||
25 | from wic.utils.misc import exec_native_cmd | ||
26 | from wic.filemap import sparse_copy | ||
27 | |||
28 | # Overhead of the MBR partitioning scheme (just one sector) | ||
29 | MBR_OVERHEAD = 1 | ||
30 | |||
31 | # Overhead of the GPT partitioning scheme | ||
32 | GPT_OVERHEAD = 34 | ||
33 | |||
34 | # Size of a sector in bytes | ||
35 | SECTOR_SIZE = 512 | ||
36 | |||
37 | class PartitionedImage(): | ||
38 | """ | ||
39 | Partitioned image in a file. | ||
40 | """ | ||
41 | |||
42 | def __init__(self, path, ptable_format, native_sysroot=None): | ||
43 | self.path = path # Path to the image file | ||
44 | self.numpart = 0 # Number of allocated partitions | ||
45 | self.realpart = 0 # Number of partitions in the partition table | ||
46 | self.offset = 0 # Offset of next partition (in sectors) | ||
47 | self.min_size = 0 # Minimum required disk size to fit | ||
48 | # all partitions (in bytes) | ||
49 | self.ptable_format = ptable_format # Partition table format | ||
50 | # Disk system identifier | ||
51 | self.identifier = int.from_bytes(os.urandom(4), 'little') | ||
52 | |||
53 | self.partitions = [] | ||
54 | self.partimages = [] | ||
55 | # Size of a sector used in calculations | ||
56 | self.sector_size = SECTOR_SIZE | ||
57 | self.native_sysroot = native_sysroot | ||
58 | |||
59 | def add_partition(self, part): | ||
60 | """ | ||
61 | Add the next partition. Partitions have to be added in the | ||
62 | first-to-last order. | ||
63 | """ | ||
64 | part.ks_pnum = len(self.partitions) | ||
65 | |||
66 | # Converting kB to sectors for parted | ||
67 | part.size_sec = part.disk_size * 1024 // self.sector_size | ||
68 | |||
69 | self.partitions.append(part) | ||
70 | |||
71 | def layout_partitions(self): | ||
72 | """ Layout the partitions, meaning calculate the position of every | ||
73 | partition on the disk. The 'ptable_format' parameter defines the | ||
74 | partition table format and may be "msdos". """ | ||
75 | |||
76 | msger.debug("Assigning %s partitions to disks" % self.ptable_format) | ||
77 | |||
78 | # Go through partitions in the order they are added in .ks file | ||
79 | for num in range(len(self.partitions)): | ||
80 | part = self.partitions[num] | ||
81 | |||
82 | if self.ptable_format == 'msdos' and part.part_type: | ||
83 | # The --part-type can also be implemented for MBR partitions, | ||
84 | # in which case it would map to the 1-byte "partition type" | ||
85 | # filed at offset 3 of the partition entry. | ||
86 | raise ImageError("setting custom partition type is not " \ | ||
87 | "implemented for msdos partitions") | ||
88 | |||
89 | # Get the disk where the partition is located | ||
90 | self.numpart += 1 | ||
91 | if not part.no_table: | ||
92 | self.realpart += 1 | ||
93 | |||
94 | if self.numpart == 1: | ||
95 | if self.ptable_format == "msdos": | ||
96 | overhead = MBR_OVERHEAD | ||
97 | elif self.ptable_format == "gpt": | ||
98 | overhead = GPT_OVERHEAD | ||
99 | |||
100 | # Skip one sector required for the partitioning scheme overhead | ||
101 | self.offset += overhead | ||
102 | |||
103 | if self.realpart > 3: | ||
104 | # Reserve a sector for EBR for every logical partition | ||
105 | # before alignment is performed. | ||
106 | if self.ptable_format == "msdos": | ||
107 | self.offset += 1 | ||
108 | |||
109 | if part.align: | ||
110 | # If not first partition and we do have alignment set we need | ||
111 | # to align the partition. | ||
112 | # FIXME: This leaves a empty spaces to the disk. To fill the | ||
113 | # gaps we could enlargea the previous partition? | ||
114 | |||
115 | # Calc how much the alignment is off. | ||
116 | align_sectors = self.offset % (part.align * 1024 // self.sector_size) | ||
117 | |||
118 | if align_sectors: | ||
119 | # If partition is not aligned as required, we need | ||
120 | # to move forward to the next alignment point | ||
121 | align_sectors = (part.align * 1024 // self.sector_size) - align_sectors | ||
122 | |||
123 | msger.debug("Realignment for %s%s with %s sectors, original" | ||
124 | " offset %s, target alignment is %sK." % | ||
125 | (part.disk, self.numpart, align_sectors, | ||
126 | self.offset, part.align)) | ||
127 | |||
128 | # increase the offset so we actually start the partition on right alignment | ||
129 | self.offset += align_sectors | ||
130 | |||
131 | part.start = self.offset | ||
132 | self.offset += part.size_sec | ||
133 | |||
134 | part.type = 'primary' | ||
135 | if not part.no_table: | ||
136 | part.num = self.realpart | ||
137 | else: | ||
138 | part.num = 0 | ||
139 | |||
140 | if self.ptable_format == "msdos": | ||
141 | # only count the partitions that are in partition table | ||
142 | if len([p for p in self.partitions if not p.no_table]) > 4: | ||
143 | if self.realpart > 3: | ||
144 | part.type = 'logical' | ||
145 | part.num = self.realpart + 1 | ||
146 | |||
147 | msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d " | ||
148 | "sectors (%d bytes)." \ | ||
149 | % (part.mountpoint, part.disk, part.num, | ||
150 | part.start, self.offset - 1, | ||
151 | part.size_sec, part.size_sec * self.sector_size)) | ||
152 | |||
153 | # Once all the partitions have been layed out, we can calculate the | ||
154 | # minumim disk size | ||
155 | self.min_size = self.offset | ||
156 | if self.ptable_format == "gpt": | ||
157 | self.min_size += GPT_OVERHEAD | ||
158 | |||
159 | self.min_size *= self.sector_size | ||
160 | |||
161 | def _create_partition(self, device, parttype, fstype, start, size): | ||
162 | """ Create a partition on an image described by the 'device' object. """ | ||
163 | |||
164 | # Start is included to the size so we need to substract one from the end. | ||
165 | end = start + size - 1 | ||
166 | msger.debug("Added '%s' partition, sectors %d-%d, size %d sectors" % | ||
167 | (parttype, start, end, size)) | ||
168 | |||
169 | cmd = "parted -s %s unit s mkpart %s" % (device, parttype) | ||
170 | if fstype: | ||
171 | cmd += " %s" % fstype | ||
172 | cmd += " %d %d" % (start, end) | ||
173 | |||
174 | return exec_native_cmd(cmd, self.native_sysroot) | ||
175 | |||
176 | def create(self): | ||
177 | msger.debug("Creating sparse file %s" % self.path) | ||
178 | with open(self.path, 'w') as sparse: | ||
179 | os.ftruncate(sparse.fileno(), self.min_size) | ||
180 | |||
181 | msger.debug("Initializing partition table for %s" % self.path) | ||
182 | exec_native_cmd("parted -s %s mklabel %s" % | ||
183 | (self.path, self.ptable_format), self.native_sysroot) | ||
184 | |||
185 | msger.debug("Set disk identifier %x" % self.identifier) | ||
186 | with open(self.path, 'r+b') as img: | ||
187 | img.seek(0x1B8) | ||
188 | img.write(self.identifier.to_bytes(4, 'little')) | ||
189 | |||
190 | msger.debug("Creating partitions") | ||
191 | |||
192 | for part in self.partitions: | ||
193 | if part.num == 0: | ||
194 | continue | ||
195 | |||
196 | if self.ptable_format == "msdos" and part.num == 5: | ||
197 | # Create an extended partition (note: extended | ||
198 | # partition is described in MBR and contains all | ||
199 | # logical partitions). The logical partitions save a | ||
200 | # sector for an EBR just before the start of a | ||
201 | # partition. The extended partition must start one | ||
202 | # sector before the start of the first logical | ||
203 | # partition. This way the first EBR is inside of the | ||
204 | # extended partition. Since the extended partitions | ||
205 | # starts a sector before the first logical partition, | ||
206 | # add a sector at the back, so that there is enough | ||
207 | # room for all logical partitions. | ||
208 | self._create_partition(self.path, "extended", | ||
209 | None, part.start - 1, | ||
210 | self.offset - part.start + 1) | ||
211 | |||
212 | if part.fstype == "swap": | ||
213 | parted_fs_type = "linux-swap" | ||
214 | elif part.fstype == "vfat": | ||
215 | parted_fs_type = "fat32" | ||
216 | elif part.fstype == "msdos": | ||
217 | parted_fs_type = "fat16" | ||
218 | elif part.fstype == "ontrackdm6aux3": | ||
219 | parted_fs_type = "ontrackdm6aux3" | ||
220 | else: | ||
221 | # Type for ext2/ext3/ext4/btrfs | ||
222 | parted_fs_type = "ext2" | ||
223 | |||
224 | # Boot ROM of OMAP boards require vfat boot partition to have an | ||
225 | # even number of sectors. | ||
226 | if part.mountpoint == "/boot" and part.fstype in ["vfat", "msdos"] \ | ||
227 | and part.size_sec % 2: | ||
228 | msger.debug("Subtracting one sector from '%s' partition to " \ | ||
229 | "get even number of sectors for the partition" % \ | ||
230 | part.mountpoint) | ||
231 | part.size_sec -= 1 | ||
232 | |||
233 | self._create_partition(self.path, part.type, | ||
234 | parted_fs_type, part.start, part.size_sec) | ||
235 | |||
236 | if part.part_type: | ||
237 | msger.debug("partition %d: set type UID to %s" % \ | ||
238 | (part.num, part.part_type)) | ||
239 | exec_native_cmd("sgdisk --typecode=%d:%s %s" % \ | ||
240 | (part.num, part.part_type, | ||
241 | self.path), self.native_sysroot) | ||
242 | |||
243 | if part.uuid and self.ptable_format == "gpt": | ||
244 | msger.debug("partition %d: set UUID to %s" % \ | ||
245 | (part.num, part.uuid)) | ||
246 | exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ | ||
247 | (part.num, part.uuid, self.path), | ||
248 | self.native_sysroot) | ||
249 | |||
250 | if part.label and self.ptable_format == "gpt": | ||
251 | msger.debug("partition %d: set name to %s" % \ | ||
252 | (part.num, part.label)) | ||
253 | exec_native_cmd("parted -s %s name %d %s" % \ | ||
254 | (self.path, part.num, part.label), | ||
255 | self.native_sysroot) | ||
256 | |||
257 | if part.active: | ||
258 | flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot" | ||
259 | msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \ | ||
260 | (flag_name, part.num, self.path)) | ||
261 | exec_native_cmd("parted -s %s set %d %s on" % \ | ||
262 | (self.path, part.num, flag_name), | ||
263 | self.native_sysroot) | ||
264 | if part.system_id: | ||
265 | exec_native_cmd("sfdisk --part-type %s %s %s" % \ | ||
266 | (self.path, part.num, part.system_id), | ||
267 | self.native_sysroot) | ||
268 | |||
269 | # Parted defaults to enabling the lba flag for fat16 partitions, | ||
270 | # which causes compatibility issues with some firmware (and really | ||
271 | # isn't necessary). | ||
272 | if parted_fs_type == "fat16": | ||
273 | if self.ptable_format == 'msdos': | ||
274 | msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \ | ||
275 | (part.num, self.path)) | ||
276 | exec_native_cmd("parted -s %s set %d lba off" % \ | ||
277 | (self.path, part.num), | ||
278 | self.native_sysroot) | ||
279 | |||
280 | def cleanup(self): | ||
281 | # remove partition images | ||
282 | for image in self.partimages: | ||
283 | os.remove(image) | ||
284 | |||
285 | def assemble(self): | ||
286 | msger.debug("Installing partitions") | ||
287 | |||
288 | for part in self.partitions: | ||
289 | source = part.source_file | ||
290 | if source: | ||
291 | # install source_file contents into a partition | ||
292 | sparse_copy(source, self.path, part.start * self.sector_size) | ||
293 | |||
294 | msger.debug("Installed %s in partition %d, sectors %d-%d, " | ||
295 | "size %d sectors" % \ | ||
296 | (source, part.num, part.start, | ||
297 | part.start + part.size_sec - 1, part.size_sec)) | ||
298 | |||
299 | partimage = self.path + '.p%d' % part.num | ||
300 | os.rename(source, partimage) | ||
301 | self.partimages.append(partimage) | ||