summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins/imager/direct.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins/imager/direct.py')
-rw-r--r--scripts/lib/wic/plugins/imager/direct.py134
1 files changed, 104 insertions, 30 deletions
diff --git a/scripts/lib/wic/plugins/imager/direct.py b/scripts/lib/wic/plugins/imager/direct.py
index ea709e8c54..a1d152659b 100644
--- a/scripts/lib/wic/plugins/imager/direct.py
+++ b/scripts/lib/wic/plugins/imager/direct.py
@@ -77,7 +77,8 @@ class DirectPlugin(ImagerPlugin):
77 77
78 image_path = self._full_path(self.workdir, self.parts[0].disk, "direct") 78 image_path = self._full_path(self.workdir, self.parts[0].disk, "direct")
79 self._image = PartitionedImage(image_path, self.ptable_format, 79 self._image = PartitionedImage(image_path, self.ptable_format,
80 self.parts, self.native_sysroot) 80 self.parts, self.native_sysroot,
81 options.extra_space)
81 82
82 def setup_workdir(self, workdir): 83 def setup_workdir(self, workdir):
83 if workdir: 84 if workdir:
@@ -116,7 +117,7 @@ class DirectPlugin(ImagerPlugin):
116 updated = False 117 updated = False
117 for part in self.parts: 118 for part in self.parts:
118 if not part.realnum or not part.mountpoint \ 119 if not part.realnum or not part.mountpoint \
119 or part.mountpoint == "/": 120 or part.mountpoint == "/" or not (part.mountpoint.startswith('/') or part.mountpoint == "swap"):
120 continue 121 continue
121 122
122 if part.use_uuid: 123 if part.use_uuid:
@@ -137,8 +138,9 @@ class DirectPlugin(ImagerPlugin):
137 device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum) 138 device_name = "/dev/%s%s%d" % (part.disk, prefix, part.realnum)
138 139
139 opts = part.fsopts if part.fsopts else "defaults" 140 opts = part.fsopts if part.fsopts else "defaults"
141 passno = part.fspassno if part.fspassno else "0"
140 line = "\t".join([device_name, part.mountpoint, part.fstype, 142 line = "\t".join([device_name, part.mountpoint, part.fstype,
141 opts, "0", "0"]) + "\n" 143 opts, "0", passno]) + "\n"
142 144
143 fstab_lines.append(line) 145 fstab_lines.append(line)
144 updated = True 146 updated = True
@@ -147,6 +149,9 @@ class DirectPlugin(ImagerPlugin):
147 self.updated_fstab_path = os.path.join(self.workdir, "fstab") 149 self.updated_fstab_path = os.path.join(self.workdir, "fstab")
148 with open(self.updated_fstab_path, "w") as f: 150 with open(self.updated_fstab_path, "w") as f:
149 f.writelines(fstab_lines) 151 f.writelines(fstab_lines)
152 if os.getenv('SOURCE_DATE_EPOCH'):
153 fstab_time = int(os.getenv('SOURCE_DATE_EPOCH'))
154 os.utime(self.updated_fstab_path, (fstab_time, fstab_time))
150 155
151 def _full_path(self, path, name, extention): 156 def _full_path(self, path, name, extention):
152 """ Construct full file path to a file we generate. """ 157 """ Construct full file path to a file we generate. """
@@ -258,6 +263,8 @@ class DirectPlugin(ImagerPlugin):
258 if part.mountpoint == "/": 263 if part.mountpoint == "/":
259 if part.uuid: 264 if part.uuid:
260 return "PARTUUID=%s" % part.uuid 265 return "PARTUUID=%s" % part.uuid
266 elif part.label and self.ptable_format != 'msdos':
267 return "PARTLABEL=%s" % part.label
261 else: 268 else:
262 suffix = 'p' if part.disk.startswith('mmcblk') else '' 269 suffix = 'p' if part.disk.startswith('mmcblk') else ''
263 return "/dev/%s%s%-d" % (part.disk, suffix, part.realnum) 270 return "/dev/%s%s%-d" % (part.disk, suffix, part.realnum)
@@ -293,7 +300,7 @@ class PartitionedImage():
293 Partitioned image in a file. 300 Partitioned image in a file.
294 """ 301 """
295 302
296 def __init__(self, path, ptable_format, partitions, native_sysroot=None): 303 def __init__(self, path, ptable_format, partitions, native_sysroot=None, extra_space=0):
297 self.path = path # Path to the image file 304 self.path = path # Path to the image file
298 self.numpart = 0 # Number of allocated partitions 305 self.numpart = 0 # Number of allocated partitions
299 self.realpart = 0 # Number of partitions in the partition table 306 self.realpart = 0 # Number of partitions in the partition table
@@ -306,7 +313,10 @@ class PartitionedImage():
306 # all partitions (in bytes) 313 # all partitions (in bytes)
307 self.ptable_format = ptable_format # Partition table format 314 self.ptable_format = ptable_format # Partition table format
308 # Disk system identifier 315 # Disk system identifier
309 self.identifier = random.SystemRandom().randint(1, 0xffffffff) 316 if os.getenv('SOURCE_DATE_EPOCH'):
317 self.identifier = random.Random(int(os.getenv('SOURCE_DATE_EPOCH'))).randint(1, 0xffffffff)
318 else:
319 self.identifier = random.SystemRandom().randint(1, 0xffffffff)
310 320
311 self.partitions = partitions 321 self.partitions = partitions
312 self.partimages = [] 322 self.partimages = []
@@ -314,6 +324,7 @@ class PartitionedImage():
314 self.sector_size = SECTOR_SIZE 324 self.sector_size = SECTOR_SIZE
315 self.native_sysroot = native_sysroot 325 self.native_sysroot = native_sysroot
316 num_real_partitions = len([p for p in self.partitions if not p.no_table]) 326 num_real_partitions = len([p for p in self.partitions if not p.no_table])
327 self.extra_space = extra_space
317 328
318 # calculate the real partition number, accounting for partitions not 329 # calculate the real partition number, accounting for partitions not
319 # in the partition table and logical partitions 330 # in the partition table and logical partitions
@@ -331,7 +342,7 @@ class PartitionedImage():
331 # generate parition and filesystem UUIDs 342 # generate parition and filesystem UUIDs
332 for part in self.partitions: 343 for part in self.partitions:
333 if not part.uuid and part.use_uuid: 344 if not part.uuid and part.use_uuid:
334 if self.ptable_format == 'gpt': 345 if self.ptable_format in ('gpt', 'gpt-hybrid'):
335 part.uuid = str(uuid.uuid4()) 346 part.uuid = str(uuid.uuid4())
336 else: # msdos partition table 347 else: # msdos partition table
337 part.uuid = '%08x-%02d' % (self.identifier, part.realnum) 348 part.uuid = '%08x-%02d' % (self.identifier, part.realnum)
@@ -387,6 +398,10 @@ class PartitionedImage():
387 raise WicError("setting custom partition type is not " \ 398 raise WicError("setting custom partition type is not " \
388 "implemented for msdos partitions") 399 "implemented for msdos partitions")
389 400
401 if part.mbr and self.ptable_format != 'gpt-hybrid':
402 raise WicError("Partition may only be included in MBR with " \
403 "a gpt-hybrid partition table")
404
390 # Get the disk where the partition is located 405 # Get the disk where the partition is located
391 self.numpart += 1 406 self.numpart += 1
392 if not part.no_table: 407 if not part.no_table:
@@ -395,7 +410,7 @@ class PartitionedImage():
395 if self.numpart == 1: 410 if self.numpart == 1:
396 if self.ptable_format == "msdos": 411 if self.ptable_format == "msdos":
397 overhead = MBR_OVERHEAD 412 overhead = MBR_OVERHEAD
398 elif self.ptable_format == "gpt": 413 elif self.ptable_format in ("gpt", "gpt-hybrid"):
399 overhead = GPT_OVERHEAD 414 overhead = GPT_OVERHEAD
400 415
401 # Skip one sector required for the partitioning scheme overhead 416 # Skip one sector required for the partitioning scheme overhead
@@ -479,10 +494,11 @@ class PartitionedImage():
479 # Once all the partitions have been layed out, we can calculate the 494 # Once all the partitions have been layed out, we can calculate the
480 # minumim disk size 495 # minumim disk size
481 self.min_size = self.offset 496 self.min_size = self.offset
482 if self.ptable_format == "gpt": 497 if self.ptable_format in ("gpt", "gpt-hybrid"):
483 self.min_size += GPT_OVERHEAD 498 self.min_size += GPT_OVERHEAD
484 499
485 self.min_size *= self.sector_size 500 self.min_size *= self.sector_size
501 self.min_size += self.extra_space
486 502
487 def _create_partition(self, device, parttype, fstype, start, size): 503 def _create_partition(self, device, parttype, fstype, start, size):
488 """ Create a partition on an image described by the 'device' object. """ 504 """ Create a partition on an image described by the 'device' object. """
@@ -499,22 +515,49 @@ class PartitionedImage():
499 515
500 return exec_native_cmd(cmd, self.native_sysroot) 516 return exec_native_cmd(cmd, self.native_sysroot)
501 517
518 def _write_identifier(self, device, identifier):
519 logger.debug("Set disk identifier %x", identifier)
520 with open(device, 'r+b') as img:
521 img.seek(0x1B8)
522 img.write(identifier.to_bytes(4, 'little'))
523
524 def _make_disk(self, device, ptable_format, min_size):
525 logger.debug("Creating sparse file %s", device)
526 with open(device, 'w') as sparse:
527 os.ftruncate(sparse.fileno(), min_size)
528
529 logger.debug("Initializing partition table for %s", device)
530 exec_native_cmd("parted -s %s mklabel %s" % (device, ptable_format),
531 self.native_sysroot)
532
533 def _write_disk_guid(self):
534 if self.ptable_format in ('gpt', 'gpt-hybrid'):
535 if os.getenv('SOURCE_DATE_EPOCH'):
536 self.disk_guid = uuid.UUID(int=int(os.getenv('SOURCE_DATE_EPOCH')))
537 else:
538 self.disk_guid = uuid.uuid4()
539
540 logger.debug("Set disk guid %s", self.disk_guid)
541 sfdisk_cmd = "sfdisk --disk-id %s %s" % (self.path, self.disk_guid)
542 exec_native_cmd(sfdisk_cmd, self.native_sysroot)
543
502 def create(self): 544 def create(self):
503 logger.debug("Creating sparse file %s", self.path) 545 self._make_disk(self.path,
504 with open(self.path, 'w') as sparse: 546 "gpt" if self.ptable_format == "gpt-hybrid" else self.ptable_format,
505 os.ftruncate(sparse.fileno(), self.min_size) 547 self.min_size)
506 548
507 logger.debug("Initializing partition table for %s", self.path) 549 self._write_identifier(self.path, self.identifier)
508 exec_native_cmd("parted -s %s mklabel %s" % 550 self._write_disk_guid()
509 (self.path, self.ptable_format), self.native_sysroot)
510 551
511 logger.debug("Set disk identifier %x", self.identifier) 552 if self.ptable_format == "gpt-hybrid":
512 with open(self.path, 'r+b') as img: 553 mbr_path = self.path + ".mbr"
513 img.seek(0x1B8) 554 self._make_disk(mbr_path, "msdos", self.min_size)
514 img.write(self.identifier.to_bytes(4, 'little')) 555 self._write_identifier(mbr_path, self.identifier)
515 556
516 logger.debug("Creating partitions") 557 logger.debug("Creating partitions")
517 558
559 hybrid_mbr_part_num = 0
560
518 for part in self.partitions: 561 for part in self.partitions:
519 if part.num == 0: 562 if part.num == 0:
520 continue 563 continue
@@ -559,11 +602,19 @@ class PartitionedImage():
559 self._create_partition(self.path, part.type, 602 self._create_partition(self.path, part.type,
560 parted_fs_type, part.start, part.size_sec) 603 parted_fs_type, part.start, part.size_sec)
561 604
562 if part.part_name: 605 if self.ptable_format == "gpt-hybrid" and part.mbr:
606 hybrid_mbr_part_num += 1
607 if hybrid_mbr_part_num > 4:
608 raise WicError("Extended MBR partitions are not supported in hybrid MBR")
609 self._create_partition(mbr_path, "primary",
610 parted_fs_type, part.start, part.size_sec)
611
612 if self.ptable_format in ("gpt", "gpt-hybrid") and (part.part_name or part.label):
613 partition_label = part.part_name if part.part_name else part.label
563 logger.debug("partition %d: set name to %s", 614 logger.debug("partition %d: set name to %s",
564 part.num, part.part_name) 615 part.num, partition_label)
565 exec_native_cmd("sgdisk --change-name=%d:%s %s" % \ 616 exec_native_cmd("sgdisk --change-name=%d:%s %s" % \
566 (part.num, part.part_name, 617 (part.num, partition_label,
567 self.path), self.native_sysroot) 618 self.path), self.native_sysroot)
568 619
569 if part.part_type: 620 if part.part_type:
@@ -573,32 +624,55 @@ class PartitionedImage():
573 (part.num, part.part_type, 624 (part.num, part.part_type,
574 self.path), self.native_sysroot) 625 self.path), self.native_sysroot)
575 626
576 if part.uuid and self.ptable_format == "gpt": 627 if part.uuid and self.ptable_format in ("gpt", "gpt-hybrid"):
577 logger.debug("partition %d: set UUID to %s", 628 logger.debug("partition %d: set UUID to %s",
578 part.num, part.uuid) 629 part.num, part.uuid)
579 exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \ 630 exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
580 (part.num, part.uuid, self.path), 631 (part.num, part.uuid, self.path),
581 self.native_sysroot) 632 self.native_sysroot)
582 633
583 if part.label and self.ptable_format == "gpt":
584 logger.debug("partition %d: set name to %s",
585 part.num, part.label)
586 exec_native_cmd("parted -s %s name %d %s" % \
587 (self.path, part.num, part.label),
588 self.native_sysroot)
589
590 if part.active: 634 if part.active:
591 flag_name = "legacy_boot" if self.ptable_format == 'gpt' else "boot" 635 flag_name = "legacy_boot" if self.ptable_format in ('gpt', 'gpt-hybrid') else "boot"
592 logger.debug("Set '%s' flag for partition '%s' on disk '%s'", 636 logger.debug("Set '%s' flag for partition '%s' on disk '%s'",
593 flag_name, part.num, self.path) 637 flag_name, part.num, self.path)
594 exec_native_cmd("parted -s %s set %d %s on" % \ 638 exec_native_cmd("parted -s %s set %d %s on" % \
595 (self.path, part.num, flag_name), 639 (self.path, part.num, flag_name),
596 self.native_sysroot) 640 self.native_sysroot)
641 if self.ptable_format == 'gpt-hybrid' and part.mbr:
642 exec_native_cmd("parted -s %s set %d %s on" % \
643 (mbr_path, hybrid_mbr_part_num, "boot"),
644 self.native_sysroot)
597 if part.system_id: 645 if part.system_id:
598 exec_native_cmd("sfdisk --part-type %s %s %s" % \ 646 exec_native_cmd("sfdisk --part-type %s %s %s" % \
599 (self.path, part.num, part.system_id), 647 (self.path, part.num, part.system_id),
600 self.native_sysroot) 648 self.native_sysroot)
601 649
650 if part.hidden and self.ptable_format == "gpt":
651 logger.debug("Set hidden attribute for partition '%s' on disk '%s'",
652 part.num, self.path)
653 exec_native_cmd("sfdisk --part-attrs %s %s RequiredPartition" % \
654 (self.path, part.num),
655 self.native_sysroot)
656
657 if self.ptable_format == "gpt-hybrid":
658 # Write a protective GPT partition
659 hybrid_mbr_part_num += 1
660 if hybrid_mbr_part_num > 4:
661 raise WicError("Extended MBR partitions are not supported in hybrid MBR")
662
663 # parted cannot directly create a protective GPT partition, so
664 # create with an arbitrary type, then change it to the correct type
665 # with sfdisk
666 self._create_partition(mbr_path, "primary", "fat32", 1, GPT_OVERHEAD)
667 exec_native_cmd("sfdisk --part-type %s %d 0xee" % (mbr_path, hybrid_mbr_part_num),
668 self.native_sysroot)
669
670 # Copy hybrid MBR
671 with open(mbr_path, "rb") as mbr_file:
672 with open(self.path, "r+b") as image_file:
673 mbr = mbr_file.read(512)
674 image_file.write(mbr)
675
602 def cleanup(self): 676 def cleanup(self):
603 pass 677 pass
604 678