Revision 25cdca3e snf-image-helper/disklabel.py
b/snf-image-helper/disklabel.py | ||
---|---|---|
171 | 171 |
d.seek(BLOCKSIZE * self.mbr.part[i].first_sector) |
172 | 172 |
self.part_num = i |
173 | 173 |
if ptype == 0xa5: # FreeBSD |
174 |
self.disklabel = BSDDisklabel(d) |
|
174 |
self.disklabel = FreeBSDDisklabel(d)
|
|
175 | 175 |
elif ptype == 0xa6: # OpenBSD |
176 | 176 |
self.disklabel = OpenBSDDisklabel(d) |
177 | 177 |
else: # NetBSD |
178 |
self.disklabel = BSDDisklabel(d) |
|
178 |
self.disklabel = NetBSDDisklabel(d)
|
|
179 | 179 |
break |
180 | 180 |
|
181 | 181 |
assert self.disklabel is not None, "No *BSD partition found" |
... | ... | |
303 | 303 |
return (cylinder, header, sector) |
304 | 304 |
|
305 | 305 |
@abc.abstractmethod |
306 |
def enlarge(self, new_size): |
|
307 |
"""Enlarge the disk and return the last usable sector""" |
|
308 |
pass |
|
309 |
|
|
310 |
@abc.abstractmethod |
|
311 |
def enlarge_last_partition(self): |
|
312 |
"""Enlarge the last partition to consume all the usable space""" |
|
313 |
pass |
|
314 |
|
|
315 |
@abc.abstractmethod |
|
316 | 306 |
def get_last_partition_id(self): |
317 | 307 |
"""Get the ID of the last partition""" |
318 | 308 |
pass |
... | ... | |
322 | 312 |
"""Print the Disklabel""" |
323 | 313 |
pass |
324 | 314 |
|
315 |
def enlarge(self, new_size): |
|
316 |
"""Enlarge the disk and return the last usable sector""" |
|
317 |
raise NotImplementedError |
|
318 |
|
|
319 |
def enlarge_last_partition(self): |
|
320 |
"""Enlarge the last partition to consume all the usable space""" |
|
321 |
raise NotImplementedError |
|
322 |
|
|
323 |
|
|
325 | 324 |
|
326 | 325 |
class PartitionTableBase(object): |
327 | 326 |
"""Base Class for disklabel partition tables""" |
... | ... | |
391 | 390 |
'cpg' # 14 2 File system cylinders per group |
392 | 391 |
] |
393 | 392 |
|
393 |
def setsize(self, i, size): |
|
394 |
"""Set size for partition i""" |
|
395 |
tmp = self.part[i] |
|
396 |
self.part[i] = self.Partition(size, tmp.offset, tmp.fsize, |
|
397 |
tmp.fstype, tmp.frag, tmp.cpg) |
|
398 |
|
|
394 | 399 |
@property |
395 | 400 |
def fmt(self): |
396 | 401 |
return "<IHH16s16sIIIIIIHHIHHHHIII20s20sIHHII364s" |
... | ... | |
440 | 445 |
self.field = d_ |
441 | 446 |
|
442 | 447 |
def enlarge(self, new_size): |
448 |
"""Enlarge the disk and return the last usable sector""" |
|
443 | 449 |
raise NotImplementedError |
444 | 450 |
|
445 | 451 |
def enlarge_last_partition(self): |
446 | 452 |
raise NotImplementedError |
447 | 453 |
|
448 | 454 |
def get_last_partition_id(self): |
449 |
raise NotImplementedError |
|
450 |
|
|
451 |
def lba2chs(self, lba, hpc=None, spt=None): |
|
452 |
"""Return the CHS address for a given LBA address""" |
|
453 |
|
|
454 |
# NetBSD uses LBA-Assisted translation. The sectors per track (spt) |
|
455 |
# value is always 63 and the heads per cylinder (hpc) value depends on |
|
456 |
# the size of the disk |
|
457 |
|
|
458 |
disk_size = self.field['secperunit'] |
|
459 |
|
|
460 |
# Maximum disk size that can be addressed is 1024 * HPC* SPT |
|
461 |
spt = 63 |
|
462 |
for hpc in 16, 32, 64, 128, 255: |
|
463 |
if disk_size <= 1024 * hpc * spt: |
|
464 |
break |
|
455 |
"""Returns the id of the last partition""" |
|
456 |
end = 0 |
|
465 | 457 |
|
466 |
chs = super(BSDDisklabel, self).lba2chs(lba, hpc, spt) |
|
458 |
# Exclude partition 'c' which describes the whole disk |
|
459 |
for i in [n for n in range(len(self.ptable.part)) if n != 2]: |
|
460 |
current_end = self.ptable.part[i].size + self.ptable.part[i].offset |
|
461 |
if end < current_end: |
|
462 |
end = current_end |
|
463 |
part = i |
|
467 | 464 |
|
468 |
if chs[0] > 1023: # Cylinders overflowed |
|
469 |
assert hpc == 255 # Cylinders may overflow only for large disks |
|
470 |
return (1023, chs[1], chs[2]) |
|
465 |
assert end > 0, "No partition found" |
|
471 | 466 |
|
472 |
return chs
|
|
467 |
return part
|
|
473 | 468 |
|
474 | 469 |
def __str__(self): |
475 | 470 |
"""Print the Disklabel""" |
... | ... | |
513 | 508 |
"%s" % self.ptable |
514 | 509 |
|
515 | 510 |
|
511 |
class FreeBSDDisklabel(BSDDisklabel): |
|
512 |
"""Represents a FreeBSD Disklabel""" |
|
513 |
pass |
|
514 |
|
|
515 |
|
|
516 |
class NetBSDDisklabel(BSDDisklabel): |
|
517 |
"""Represents a NetBSD Disklabel""" |
|
518 |
|
|
519 |
def lba2chs(self, lba, hpc=None, spt=None): |
|
520 |
"""Return the CHS address for a given LBA address""" |
|
521 |
|
|
522 |
# NetBSD uses LBA-Assisted translation. The sectors per track (spt) |
|
523 |
# value is always 63 and the heads per cylinder (hpc) value depends on |
|
524 |
# the size of the disk |
|
525 |
|
|
526 |
disk_size = self.field['secperunit'] |
|
527 |
|
|
528 |
# Maximum disk size that can be addressed is 1024 * HPC* SPT |
|
529 |
spt = 63 |
|
530 |
for hpc in 16, 32, 64, 128, 255: |
|
531 |
if disk_size <= 1024 * hpc * spt: |
|
532 |
break |
|
533 |
|
|
534 |
chs = super(NetBSDDisklabel, self).lba2chs(lba, hpc, spt) |
|
535 |
|
|
536 |
if chs[0] > 1023: # Cylinders overflowed |
|
537 |
assert hpc == 255 # Cylinders may overflow only for large disks |
|
538 |
return (1023, chs[1], chs[2]) |
|
539 |
|
|
540 |
return chs |
|
541 |
|
|
542 |
def enlarge(self, new_size): |
|
543 |
"""Enlarge the disk and return the last usable sector""" |
|
544 |
|
|
545 |
assert new_size >= self.field['secperunit'], \ |
|
546 |
"New size cannot be smaller than %d" % self.field['secperunit'] |
|
547 |
|
|
548 |
self.field['secperunit'] = new_size |
|
549 |
|
|
550 |
# According to the ATA specifications, "If the content of words (61:60) |
|
551 |
# is greater than or equal to 16,514,064 then the content of word 1 |
|
552 |
# [the number of logical cylinders] shall be equal to 16,383." |
|
553 |
# NetBSD respects this. |
|
554 |
self.field['ncylinders'] = 16383 if new_size >= 16514064 else \ |
|
555 |
new_size // self.field['secpercyl'] |
|
556 |
|
|
557 |
# Partition 'c' describes the NetBSD MBR partition |
|
558 |
self.ptable.setsize(2, new_size - self.ptable.part[2].offset) |
|
559 |
|
|
560 |
# Partition 'd' describes the entire disk |
|
561 |
self.ptable.setsize(3, new_size) |
|
562 |
|
|
563 |
# Update the checksum |
|
564 |
self.field['checksum'] = self.compute_checksum() |
|
565 |
|
|
566 |
return new_size - 1 |
|
567 |
|
|
568 |
def enlarge_last_partition(self): |
|
569 |
"""Enlarge the last partition to cover up all the free space""" |
|
570 |
|
|
571 |
last = self.get_last_partition_id() |
|
572 |
size = self.field['secperunit'] - self.ptable.part[last].offset |
|
573 |
self.ptable.setsize(last, size) |
|
574 |
|
|
575 |
self.field['checksum'] = self.compute_checksum() |
|
576 |
|
|
577 |
def get_last_partition_id(self): |
|
578 |
"""Returns the id of the last partition""" |
|
579 |
end = 0 |
|
580 |
|
|
581 |
# Exclude partition 'c' which describes the NetBSD MBR partition and |
|
582 |
# partition 'd' which describes the whole disk |
|
583 |
for i in [n for n in range(len(self.ptable.part)) if n not in (2, 3)]: |
|
584 |
current_end = self.ptable.part[i].size + self.ptable.part[i].offset |
|
585 |
if end < current_end: |
|
586 |
end = current_end |
|
587 |
part = i |
|
588 |
|
|
589 |
assert end > 0, "No partition found" |
|
590 |
|
|
591 |
return part |
|
592 |
|
|
593 |
|
|
516 | 594 |
class OpenBSDDisklabel(DisklabelBase): |
517 | 595 |
"""Represents an OpenBSD Disklabel""" |
518 | 596 |
|
... | ... | |
642 | 720 |
"""Enlarge the disk and return the last usable sector""" |
643 | 721 |
|
644 | 722 |
assert new_size >= self.dsize, \ |
645 |
"New size cannot be smaller that %s" % self.dsize
|
|
723 |
"New size cannot be smaller than %d" % self.dsize
|
|
646 | 724 |
|
647 | 725 |
# Fix the disklabel |
648 | 726 |
self.dsize = new_size |
... | ... | |
651 | 729 |
self.bend = (self.field['ncylinders'] * self.field['nsectors'] * |
652 | 730 |
self.field['ntracks']) |
653 | 731 |
|
654 |
# Partition 'c' descriptes the entire disk
|
|
732 |
# Partition 'c' describes the entire disk
|
|
655 | 733 |
self.ptable.setpsize(2, new_size) |
656 | 734 |
|
657 | 735 |
# Update the checksum |
... | ... | |
662 | 740 |
|
663 | 741 |
def get_last_partition_id(self): |
664 | 742 |
"""Returns the id of the last partition""" |
665 |
part = 0 |
|
666 | 743 |
end = 0 |
667 | 744 |
# Don't check partition 'c' which is the whole disk |
668 |
for i in filter(lambda x: x != 2, range(len(self.ptable.part))):
|
|
745 |
for i in [n for n in range(len(self.ptable.part)) if n != 2]:
|
|
669 | 746 |
curr_end = self.ptable.getpsize(i) + self.ptable.getpoffset(i) |
670 | 747 |
if end < curr_end: |
671 | 748 |
end = curr_end |
Also available in: Unified diff