summaryrefslogtreecommitdiffstats
path: root/scripts/lib
diff options
context:
space:
mode:
authorEd Bartosh <ed.bartosh@linux.intel.com>2017-02-09 16:28:54 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-02-15 20:06:44 -0800
commitcdcc6e27530f13531b3bda9a15dc926f6ff9a837 (patch)
treea1993d5b949cde736661ffae78d55ac1b485eaa4 /scripts/lib
parentadf5e2956ca4e3136be0ee785115a7e1941a135b (diff)
downloadpoky-cdcc6e27530f13531b3bda9a15dc926f6ff9a837.tar.gz
wic: move PartitionedImage class to direct.py
As PartitionedImage is only used in direct.py it makes sense to move it there. It's easier to maintain (and refactor) it this way. (From OE-Core rev: 2550622371f5c50857e5d58eabab01a1823c6fc3) Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib')
-rw-r--r--scripts/lib/wic/plugins/imager/direct.py278
-rw-r--r--scripts/lib/wic/utils/partitionedfs.py301
2 files changed, 276 insertions, 303 deletions
diff --git a/scripts/lib/wic/plugins/imager/direct.py b/scripts/lib/wic/plugins/imager/direct.py
index fefe88e0df..12044318e8 100644
--- a/scripts/lib/wic/plugins/imager/direct.py
+++ b/scripts/lib/wic/plugins/imager/direct.py
@@ -31,13 +31,12 @@ import tempfile
31from time import strftime 31from time import strftime
32 32
33from wic import msger 33from wic import msger
34from wic.filemap import sparse_copy
34from wic.ksparser import KickStart, KickStartError 35from wic.ksparser import KickStart, KickStartError
35from wic.plugin import pluginmgr 36from wic.plugin import pluginmgr
36from wic.pluginbase import ImagerPlugin 37from wic.pluginbase import ImagerPlugin
37from wic.utils.errors import CreatorError, ImageError 38from wic.utils.errors import CreatorError, ImageError
38from wic.utils.misc import get_bitbake_var, exec_cmd, exec_native_cmd 39from wic.utils.misc import get_bitbake_var, exec_cmd, exec_native_cmd
39from wic.utils.partitionedfs import PartitionedImage
40
41 40
42class DirectPlugin(ImagerPlugin): 41class DirectPlugin(ImagerPlugin):
43 """ 42 """
@@ -316,3 +315,278 @@ class DirectPlugin(ImagerPlugin):
316 315
317 # remove work directory 316 # remove work directory
318 shutil.rmtree(self.workdir, ignore_errors=True) 317 shutil.rmtree(self.workdir, ignore_errors=True)
318
319# Overhead of the MBR partitioning scheme (just one sector)
320MBR_OVERHEAD = 1
321
322# Overhead of the GPT partitioning scheme
323GPT_OVERHEAD = 34
324
325# Size of a sector in bytes
326SECTOR_SIZE = 512
327
328class PartitionedImage():
329 """
330 Partitioned image in a file.
331 """
332
333 def __init__(self, path, ptable_format, native_sysroot=None):
334 self.path = path # Path to the image file
335 self.numpart = 0 # Number of allocated partitions
336 self.realpart = 0 # Number of partitions in the partition table
337 self.offset = 0 # Offset of next partition (in sectors)
338 self.min_size = 0 # Minimum required disk size to fit
339 # all partitions (in bytes)
340 self.ptable_format = ptable_format # Partition table format
341 # Disk system identifier
342 self.identifier = int.from_bytes(os.urandom(4), 'little')
343
344 self.partitions = []
345 self.partimages = []
346 # Size of a sector used in calculations
347 self.sector_size = SECTOR_SIZE
348 self.native_sysroot = native_sysroot
349
350 def add_partition(self, part):
351 """
352 Add the next partition. Partitions have to be added in the
353 first-to-last order.
354 """
355 part.ks_pnum = len(self.partitions)
356
357 # Converting kB to sectors for parted
358 part.size_sec = part.disk_size * 1024 // self.sector_size
359
360 self.partitions.append(part)
361
362 def layout_partitions(self):
363 """ Layout the partitions, meaning calculate the position of every
364 partition on the disk. The 'ptable_format' parameter defines the
365 partition table format and may be "msdos". """
366
367 msger.debug("Assigning %s partitions to disks" % self.ptable_format)
368
369 # Go through partitions in the order they are added in .ks file
370 for num in range(len(self.partitions)):
371 part = self.partitions[num]
372
373 if self.ptable_format == 'msdos' and part.part_type:
374 # The --part-type can also be implemented for MBR partitions,
375 # in which case it would map to the 1-byte "partition type"
376 # filed at offset 3 of the partition entry.
377 raise ImageError("setting custom partition type is not " \
378 "implemented for msdos partitions")
379
380 # Get the disk where the partition is located
381 self.numpart += 1
382 if not part.no_table:
383 self.realpart += 1
384
385 if self.numpart == 1:
386 if self.ptable_format == "msdos":
387 overhead = MBR_OVERHEAD
388 elif self.ptable_format == "gpt":
389 overhead = GPT_OVERHEAD
390
391 # Skip one sector required for the partitioning scheme overhead
392 self.offset += overhead
393
394 if self.realpart > 3:
395 # Reserve a sector for EBR for every logical partition
396 # before alignment is performed.
397 if self.ptable_format == "msdos":
398 self.offset += 1
399
400 if part.align:
401 # If not first partition and we do have alignment set we need
402 # to align the partition.
403 # FIXME: This leaves a empty spaces to the disk. To fill the
404 # gaps we could enlargea the previous partition?
405
406 # Calc how much the alignment is off.
407 align_sectors = self.offset % (part.align * 1024 // self.sector_size)
408
409 if align_sectors:
410 # If partition is not aligned as required, we need
411 # to move forward to the next alignment point
412 align_sectors = (part.align * 1024 // self.sector_size) - align_sectors
413
414 msger.debug("Realignment for %s%s with %s sectors, original"
415 " offset %s, target alignment is %sK." %
416 (part.disk, self.numpart, align_sectors,
417 self.offset, part.align))
418
419 # increase the offset so we actually start the partition on right alignment
420 self.offset += align_sectors
421
422 part.start = self.offset
423 self.offset += part.size_sec
424
425 part.type = 'primary'
426 if not part.no_table:
427 part.num = self.realpart
428 else:
429 part.num = 0
430
431 if self.ptable_format == "msdos":
432 # only count the partitions that are in partition table
433 if len([p for p in self.partitions if not p.no_table]) > 4:
434 if self.realpart > 3:
435 part.type = 'logical'
436 part.num = self.realpart + 1
437
438 msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d "
439 "sectors (%d bytes)." \
440 % (part.mountpoint, part.disk, part.num,
441 part.start, self.offset - 1,
442 part.size_sec, part.size_sec * self.sector_size))
443
444 # Once all the partitions have been layed out, we can calculate the
445 # minumim disk size
446 self.min_size = self.offset
447 if self.ptable_format == "gpt":
448 self.min_size += GPT_OVERHEAD
449
450 self.min_size *= self.sector_size
451
452 def _create_partition(self, device, parttype, fstype, start, size):
453 """ Create a partition on an image described by the 'device' object. """
454
455 # Start is included to the size so we need to substract one from the end.
456 end = start + size - 1
457 msger.debug("Added '%s' partition, sectors %d-%d, size %d sectors" %
458 (parttype, start, end, size))
459
460 cmd = "parted -s %s unit s mkpart %s" % (device, parttype)
461 if fstype:
462 cmd += " %s" % fstype
463 cmd += " %d %d" % (start, end)
464
465 return exec_native_cmd(cmd, self.native_sysroot)
466
467 def create(self):
468 msger.debug("Creating sparse file %s" % self.path)
469 with open(self.path, 'w') as sparse:
470 os.ftruncate(sparse.fileno(), self.min_size)
471
472 msger.debug("Initializing partition table for %s" % self.path)
473 exec_native_cmd("parted -s %s mklabel %s" %
474 (self.path, self.ptable_format), self.native_sysroot)
475
476 msger.debug("Set disk identifier %x" % self.identifier)
477 with open(self.path, 'r+b') as img:
478 img.seek(0x1B8)
479 img.write(self.identifier.to_bytes(4, 'little'))
480
481 msger.debug("Creating partitions")
482
483 for part in self.partitions:
484 if part.num == 0:
485 continue
486
487 if self.ptable_format == "msdos" and part.num == 5:
488 # Create an extended partition (note: extended
489 # partition is described in MBR and contains all
490 # logical partitions). The logical partitions save a
491 # sector for an EBR just before the start of a
492 # partition. The extended partition must start one
493 # sector before the start of the first logical
494 # partition. This way the first EBR is inside of the
495 # extended partition. Since the extended partitions
496 # starts a sector before the first logical partition,
497 # add a sector at the back, so that there is enough
498 # room for all logical partitions.
499 self._create_partition(self.path, "extended",
500 None, part.start - 1,
501 self.offset - part.start + 1)
502
503 if part.fstype == "swap":
504 parted_fs_type = "linux-swap"
505 elif part.fstype == "vfat":
506 parted_fs_type = "fat32"
507 elif part.fstype == "msdos":
508 parted_fs_type = "fat16"
509 elif part.fstype == "ontrackdm6aux3":
510 parted_fs_type = "ontrackdm6aux3"
511 else:
512 # Type for ext2/ext3/ext4/btrfs
513 parted_fs_type = "ext2"
514
515 # Boot ROM of OMAP boards require vfat boot partition to have an
516 # even number of sectors.
517 if part.mountpoint == "/boot" and part.fstype in ["vfat", "msdos"] \
518 and part.size_sec % 2:
519 msger.debug("Subtracting one sector from '%s' partition to " \
520 "get even number of sectors for the partition" % \
521 part.mountpoint)
522 part.size_sec -= 1
523
524 self._create_partition(self.path, part.type,
525 parted_fs_type, part.start, part.size_sec)
526
527 if part.part_type:
528 msger.debug("partition %d: set type UID to %s" % \
529 (part.num, part.part_type))
530 exec_native_cmd("sgdisk --typecode=%d:%s %s" % \
531 (part.num, part.part_type,
532 self.path), self.native_sysroot)
533
534 if part.uuid and self.ptable_format == "gpt":
535 msger.debug("partition %d: set UUID to %s" % \
536 (part.num, part.uuid))
537 exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
538 (part.num, part.uuid, self.path),
539 self.native_sysroot)
540
541 if part.label and self.ptable_format == "gpt":
542 msger.debug("partition %d: set name to %s" % \
543 (part.num, part.label))
544 exec_native_cmd("parted -s %s name %d %s" % \
545 (self.path, part.num, part.label),
546 self.native_sysroot)
547
548 if part.active:
549 flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot"
550 msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \
551 (flag_name, part.num, self.path))
552 exec_native_cmd("parted -s %s set %d %s on" % \
553 (self.path, part.num, flag_name),
554 self.native_sysroot)
555 if part.system_id:
556 exec_native_cmd("sfdisk --part-type %s %s %s" % \
557 (self.path, part.num, part.system_id),
558 self.native_sysroot)
559
560 # Parted defaults to enabling the lba flag for fat16 partitions,
561 # which causes compatibility issues with some firmware (and really
562 # isn't necessary).
563 if parted_fs_type == "fat16":
564 if self.ptable_format == 'msdos':
565 msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \
566 (part.num, self.path))
567 exec_native_cmd("parted -s %s set %d lba off" % \
568 (self.path, part.num),
569 self.native_sysroot)
570
571 def cleanup(self):
572 # remove partition images
573 for image in self.partimages:
574 os.remove(image)
575
576 def assemble(self):
577 msger.debug("Installing partitions")
578
579 for part in self.partitions:
580 source = part.source_file
581 if source:
582 # install source_file contents into a partition
583 sparse_copy(source, self.path, part.start * self.sector_size)
584
585 msger.debug("Installed %s in partition %d, sectors %d-%d, "
586 "size %d sectors" % \
587 (source, part.num, part.start,
588 part.start + part.size_sec - 1, part.size_sec))
589
590 partimage = self.path + '.p%d' % part.num
591 os.rename(source, partimage)
592 self.partimages.append(partimage)
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
21import os
22
23from wic import msger
24from wic.utils.errors import ImageError
25from wic.utils.misc import exec_native_cmd
26from wic.filemap import sparse_copy
27
28# Overhead of the MBR partitioning scheme (just one sector)
29MBR_OVERHEAD = 1
30
31# Overhead of the GPT partitioning scheme
32GPT_OVERHEAD = 34
33
34# Size of a sector in bytes
35SECTOR_SIZE = 512
36
37class 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)