/[soft]/drakx/trunk/perl-install/partition_table.pm
ViewVC logotype

Contents of /drakx/trunk/perl-install/partition_table.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3694 - (show annotations) (download)
Fri Mar 23 19:50:35 2012 UTC (12 years ago) by tv
File size: 20657 byte(s)
perl_checker cleanups
1 package partition_table; # $Id: partition_table.pm 268438 2010-05-10 14:25:50Z pterjan $
2
3 use diagnostics;
4 use strict;
5
6 use common;
7 use fs::type;
8 use partition_table::raw;
9 use detect_devices;
10 use log;
11
12
13 sub hd2minimal_part {
14 my ($hd) = @_;
15 {
16 rootDevice => $hd->{device},
17 if_($hd->{usb_media_type}, is_removable => 1),
18 };
19 }
20
21 #- works for both hard disk drives and partitions ;p
22 sub description {
23 my ($hd) = @_;
24 my $win = $hd->{device_windobe};
25
26 sprintf "%s%s (%s)",
27 $hd->{device},
28 $win && " [$win:]",
29 join(', ',
30 grep { $_ }
31 formatXiB($hd->{totalsectors} || $hd->{size}, 512),
32 $hd->{info}, $hd->{mntpoint}, $hd->{fs_type});
33 }
34
35 #- align partition start to the next MB boundary
36 sub align_to_MB_boundaries {
37 my ($part) = @_;
38
39 my $end = $part->{start} + $part->{size};
40 $part->{start} = round_up($part->{start}, MB(1));
41 $part->{size} = $end - $part->{start};
42 }
43
44 sub adjustStartAndEnd {
45 my ($hd, $part) = @_;
46
47 # always align partition start to MB boundaries
48 # (this accounts for devices with non-512 physical sector sizes):
49 align_to_MB_boundaries($part);
50
51 $hd->adjustStart($part);
52 $hd->adjustEnd($part);
53 }
54
55 sub verifyNotOverlap {
56 my ($a, $b) = @_;
57 $a->{start} + $a->{size} <= $b->{start} || $b->{start} + $b->{size} <= $a->{start};
58 }
59 sub verifyInside {
60 my ($a, $b) = @_;
61 $b->{start} <= $a->{start} && $a->{start} + $a->{size} <= $b->{start} + $b->{size};
62 }
63
64 sub verifyParts_ {
65 foreach my $i (@_) {
66 foreach (@_) {
67 next if !$i || !$_ || $i == $_ || isWholedisk($i) || isExtended($i); #- avoid testing twice for simplicity :-)
68 if (isWholedisk($_)) {
69 verifyInside($i, $_) or
70 cdie sprintf("partition sector #$i->{start} (%s) is not inside whole disk (%s)!",
71 formatXiB($i->{size}, 512), formatXiB($_->{size}, 512));
72 } elsif (isExtended($_)) {
73 verifyNotOverlap($i, $_) or
74 log::l(sprintf("warning partition sector #$i->{start} (%s) is overlapping with extended partition!",
75 formatXiB($i->{size}, 512))); #- only warning for this one is acceptable
76 } else {
77 verifyNotOverlap($i, $_) or
78 cdie sprintf("partitions sector #$i->{start} (%s) and sector #$_->{start} (%s) are overlapping!",
79 formatXiB($i->{size}, 512), formatXiB($_->{size}, 512));
80 }
81 }
82 }
83 }
84 sub verifyParts {
85 my ($hd) = @_;
86 verifyParts_(get_normal_parts($hd));
87 }
88 sub verifyPrimary {
89 my ($pt) = @_;
90 $_->{start} > 0 || arch() =~ /^sparc/ || die "partition must NOT start at sector 0" foreach @{$pt->{normal}};
91 verifyParts_(@{$pt->{normal}}, $pt->{extended});
92 }
93
94 sub compute_device_name {
95 my ($part, $hd) = @_;
96 $part->{device} = _compute_device_name($hd, $part->{part_number});
97 }
98
99 sub _compute_device_name {
100 my ($hd, $nb) = @_;
101 my $prefix = $hd->{prefix} || devices::prefix_for_dev($hd->{device});
102 $prefix . $nb;
103 }
104
105 sub assign_device_numbers {
106 my ($hd) = @_;
107
108 my $i = 1;
109 my $start = 1;
110
111 #- on PPC we need to assign device numbers to the holes too - big FUN!
112 #- not if it's an IBM machine using a DOS partition table though
113 if (arch() =~ /ppc/ && detect_devices::get_mac_model() !~ /^IBM/) {
114 #- first sort the normal parts
115 $hd->{primary}{normal} = [ sort { $a->{start} <=> $b->{start} } @{$hd->{primary}{normal}} ];
116
117 #- now loop through them, assigning partition numbers - reserve one for the holes
118 foreach (@{$hd->{primary}{normal}}) {
119 if ($_->{start} > $start) {
120 log::l("PPC: found a hole on $hd->{device} before $_->{start}, skipping device...");
121 $i++;
122 }
123 $_->{part_number} = $i;
124 compute_device_name($_, $hd);
125 $start = $_->{start} + $_->{size};
126 $i++;
127 }
128 } else {
129 foreach (@{$hd->{primary}{raw}}) {
130 $_->{part_number} = $i;
131 compute_device_name($_, $hd);
132 $i++;
133 }
134 foreach (map { $_->{normal} } @{$hd->{extended} || []}) {
135 my $dev = _compute_device_name($hd, $i);
136 my $renumbered = $_->{device} && $dev ne $_->{device};
137 if ($renumbered) {
138 require fs::mount;
139 eval { fs::mount::umount_part($_) }; #- at least try to umount it
140 will_tell_kernel($hd, del => $_, 'delay_del');
141 push @{$hd->{partitionsRenumbered}}, [ $_->{device}, $dev ];
142 }
143 $_->{part_number} = $i;
144 compute_device_name($_, $hd);
145 if ($renumbered) {
146 will_tell_kernel($hd, add => $_, 'delay_add');
147 }
148 $i++;
149 }
150 }
151
152 #- try to figure what the windobe drive letter could be!
153 #
154 #- first verify there's at least one primary dos partition, otherwise it
155 #- means it is a secondary disk and all will be false :(
156 #-
157 my ($c, @others) = grep { isFat_or_NTFS($_) } @{$hd->{primary}{normal}};
158
159 $i = ord 'C';
160 $c->{device_windobe} = chr($i++) if $c;
161 $_->{device_windobe} = chr($i++) foreach grep { isFat_or_NTFS($_) } map { $_->{normal} } @{$hd->{extended}};
162 $_->{device_windobe} = chr($i++) foreach @others;
163 }
164
165 sub remove_empty_extended {
166 my ($hd) = @_;
167 my $last = $hd->{primary}{extended} or return;
168 @{$hd->{extended}} = grep {
169 if ($_->{normal}) {
170 $last = $_;
171 } else {
172 %{$last->{extended}} = $_->{extended} ? %{$_->{extended}} : ();
173 }
174 $_->{normal};
175 } @{$hd->{extended}};
176 adjust_main_extended($hd);
177 }
178
179 sub adjust_main_extended {
180 my ($hd) = @_;
181
182 if (!is_empty_array_ref $hd->{extended}) {
183 my ($l, @l) = @{$hd->{extended}};
184
185 # the first is a special case, must recompute its real size
186 my $start = round_down($l->{normal}{start} - 1, $hd->{geom}{sectors});
187 my $end = $l->{normal}{start} + $l->{normal}{size};
188 my $only_linux = 1; my $has_win_lba = 0;
189 foreach (map { $_->{normal} } $l, @l) {
190 $start = min($start, $_->{start});
191 $end = max($end, $_->{start} + $_->{size});
192 $only_linux &&= isTrueLocalFS($_) || isSwap($_);
193 $has_win_lba ||= $_->{pt_type} == 0xc || $_->{pt_type} == 0xe;
194 }
195 $l->{start} = $hd->{primary}{extended}{start} = $start;
196 $l->{size} = $hd->{primary}{extended}{size} = $end - $start;
197 }
198 if (!@{$hd->{extended} || []} && $hd->{primary}{extended}) {
199 will_tell_kernel($hd, del => $hd->{primary}{extended});
200 %{$hd->{primary}{extended}} = (); #- modify the raw entry
201 delete $hd->{primary}{extended};
202 }
203 verifyParts($hd); #- verify everything is all right
204 }
205
206 sub adjust_local_extended {
207 my ($hd, $part) = @_;
208
209 my $extended = find { $_->{normal} == $part } @{$hd->{extended} || []} or return;
210 $extended->{size} = $part->{size} + $part->{start} - $extended->{start};
211
212 #- must write it there too because values are not shared
213 my $prev = find { $_->{extended}{start} == $extended->{start} } @{$hd->{extended} || []} or return;
214 $prev->{extended}{size} = $part->{size} + $part->{start} - $prev->{extended}{start};
215 }
216
217 sub get_normal_parts {
218 my ($hd) = @_;
219
220 @{$hd->{primary}{normal} || []}, map { $_->{normal} } @{$hd->{extended} || []};
221 }
222
223 sub get_normal_parts_and_holes {
224 my ($hd) = @_;
225 my ($start, $last) = ($hd->first_usable_sector, $hd->last_usable_sector);
226
227 ref($hd) or print("get_normal_parts_and_holes: bad hd" . backtrace(), "\n");
228
229 my $minimal_hole = put_in_hash({ pt_type => 0 }, hd2minimal_part($hd));
230
231 my @l = map {
232 my $current = $start;
233 $start = $_->{start} + $_->{size};
234 my $hole = { start => $current, size => $_->{start} - $current, %$minimal_hole };
235 put_in_hash($hole, hd2minimal_part($hd));
236 $hole, $_;
237 } sort { $a->{start} <=> $b->{start} } grep { !isWholedisk($_) } get_normal_parts($hd);
238
239 push @l, { start => $start, size => min($last - $start, $hd->max_partition_size), %$minimal_hole } if $start < $hd->max_partition_start;
240 grep { !isEmpty($_) || $_->{size} >= $hd->cylinder_size } @l;
241 }
242
243 sub _default_type {
244 my ($hd) = @_;
245
246 arch() =~ /ia64/ ? 'gpt' :
247 arch() eq "alpha" ? "bsd" :
248 arch() =~ /^sparc/ ? "sun" :
249 arch() eq "ppc" && detect_devices::get_mac_model() !~ /^IBM/ ? "mac" :
250 $hd->{totalsectors} > 4 * 1024 * 1024 * 2048 ? 'lvm' : "dos"; #- default to LVM on full disk when >4TB
251 }
252
253 sub initialize {
254 my ($hd, $o_type) = @_;
255
256 my $type = $o_type || _default_type($hd);
257
258 require "partition_table/$type.pm";
259 "partition_table::$type"->initialize($hd);
260
261 delete $hd->{extended};
262 if (detect_devices::is_xbox()) {
263 my $part = { start => 1, size => 15632048, pt_type => 0x0bf, isFormatted => 1 };
264 partition_table::dos::compute_CHS($hd, $part);
265 $hd->{primary}{raw}[0] = $part;
266 }
267 }
268
269 sub read_primary {
270 my ($hd) = @_;
271
272 #- it can be safely considered that the first sector is used to probe the partition table
273 #- but other sectors (typically for extended partition ones) have to match this type!
274 my @parttype = (
275 if_(arch() =~ /^ia64/, 'gpt'),
276 # gpt must be tried before dos as it presents a fake compatibility mbr
277 arch() =~ /^sparc/ ? ('sun', 'bsd') : ('gpt', 'lvm', 'dmcrypt', 'dos', 'bsd', 'sun', 'mac'),
278 );
279 foreach ('empty', @parttype, 'unknown') {
280 /unknown/ and die "unknown partition table format on disk " . $hd->{file};
281
282 # perl_checker: require partition_table::bsd
283 # perl_checker: require partition_table::dos
284 # perl_checker: require partition_table::empty
285 # perl_checker: require partition_table::dmcrypt
286 # perl_checker: require partition_table::lvm
287 # perl_checker: require partition_table::gpt
288 # perl_checker: require partition_table::mac
289 # perl_checker: require partition_table::sun
290 require "partition_table/$_.pm";
291 bless $hd, "partition_table::$_";
292 if ($hd->read_primary) {
293 log::l("found a $_ partition table on $hd->{file} at sector 0");
294 return 1;
295 }
296 }
297 0;
298 }
299
300 sub read {
301 my ($hd) = @_;
302 read_primary($hd) or return 0;
303 eval {
304 my $need_removing_empty_extended;
305 if ($hd->{primary}{extended}) {
306 read_extended($hd, $hd->{primary}{extended}, \$need_removing_empty_extended) or return 0;
307 }
308 if ($need_removing_empty_extended) {
309 #- special case when hda5 is empty, it must be skipped
310 #- (windows XP generates such partition tables)
311 remove_empty_extended($hd); #- includes adjust_main_extended
312 }
313
314 };
315 die "extended partition: $@" if $@;
316
317 assign_device_numbers($hd);
318 remove_empty_extended($hd);
319
320 $hd->set_best_geometry_for_the_partition_table;
321 1;
322 }
323
324 sub read_extended {
325 my ($hd, $extended, $need_removing_empty_extended) = @_;
326
327 my $pt = do {
328 my ($pt, $info) = $hd->read_one($extended->{start}) or return 0;
329 partition_table::raw::pt_info_to_primary($hd, $pt, $info);
330 };
331 $pt = { %$extended, %$pt };
332
333 push @{$hd->{extended}}, $pt;
334 @{$hd->{extended}} > 100 and die "oops, seems like we're looping here :( (or you have more than 100 extended partitions!)";
335
336 if (@{$pt->{normal}} == 0) {
337 $$need_removing_empty_extended = 1;
338 delete $pt->{normal};
339 print "need_removing_empty_extended\n";
340 } elsif (@{$pt->{normal}} > 1) {
341 die "more than one normal partition in extended partition";
342 } else {
343 $pt->{normal} = $pt->{normal}[0];
344 #- in case of extended partitions, the start sector is local to the partition or to the first extended_part!
345 $pt->{normal}{start} += $pt->{start};
346
347 #- the following verification can broke an existing partition table that is
348 #- correctly read by fdisk or cfdisk. maybe the extended partition can be
349 #- recomputed to get correct size.
350 if (!verifyInside($pt->{normal}, $extended)) {
351 $extended->{size} = $pt->{normal}{start} + $pt->{normal}{size};
352 verifyInside($pt->{normal}, $extended) or die "partition $pt->{normal}{device} is not inside its extended partition";
353 }
354 }
355
356 if ($pt->{extended}) {
357 $pt->{extended}{start} += $hd->{primary}{extended}{start};
358 return read_extended($hd, $pt->{extended}, $need_removing_empty_extended);
359 } else {
360 1;
361 }
362 }
363
364 sub will_tell_kernel {
365 my ($hd, $action, $o_part, $o_delay) = @_;
366
367 if ($action eq 'resize') {
368 will_tell_kernel($hd, del => $o_part);
369 will_tell_kernel($hd, add => $o_part);
370 } else {
371 my $part_number;
372 if ($o_part) {
373 ($part_number) = $o_part->{device} =~ /(\d+)$/ or
374 #- do not die, it occurs when we zero_MBR_and_dirty a raw_lvm_PV
375 log::l("ERROR: will_tell_kernel bad device " . description($o_part)), return;
376 }
377
378 my @para =
379 $action eq 'force_reboot' ? () :
380 $action eq 'add' ? ($part_number, $o_part->{start}, $o_part->{size}) :
381 $action eq 'del' ? $part_number :
382 internal_error("unknown action $action");
383
384 push @{$hd->{'will_tell_kernel' . ($o_delay || '')} ||= []}, [ $action, @para ];
385 }
386 if (!$o_delay) {
387 foreach my $delay ('delay_del', 'delay_add') {
388 my $l = delete $hd->{"will_tell_kernel$delay"} or next;
389 push @{$hd->{will_tell_kernel} ||= []}, @$l;
390 }
391 }
392 $hd->{isDirty} = 1;
393 }
394
395 sub tell_kernel {
396 my ($hd, $tell_kernel) = @_;
397
398 my $F = partition_table::raw::openit($hd);
399
400 run_program::run('udevadm', 'control', '--stop-exec-queue') unless $::isInstall;
401
402 my $force_reboot = any { $_->[0] eq 'force_reboot' } @$tell_kernel;
403 if (!$force_reboot) {
404 foreach (@$tell_kernel) {
405 my ($action, $part_number, $o_start, $o_size) = @$_;
406
407 if ($action eq 'add') {
408 $force_reboot ||= !c::add_partition(fileno($F), $part_number, $o_start, $o_size);
409 } elsif ($action eq 'del') {
410 $force_reboot ||= !c::del_partition(fileno($F), $part_number);
411 }
412 log::l("tell kernel $action ($hd->{device} $part_number $o_start $o_size) force_reboot=$force_reboot rebootNeeded=$hd->{rebootNeeded}");
413 }
414 }
415
416 run_program::run('udevadm', 'control', '--start-exec-queue') unless $::isInstall;
417
418 if ($force_reboot) {
419 # FIXME Handle LVM/dmcrypt/RAID
420 my @magic_parts = grep { $_->{isMounted} && $_->{real_mntpoint} } get_normal_parts($hd);
421 foreach (@magic_parts) {
422 syscall_('umount', $_->{real_mntpoint}) or log::l(N("error unmounting %s: %s", $_->{real_mntpoint}, $!));
423 }
424 $hd->{rebootNeeded} = !ioctl($F, c::BLKRRPART(), 0);
425 log::l("tell kernel force_reboot ($hd->{device}), rebootNeeded=$hd->{rebootNeeded}");
426
427 foreach (@magic_parts) {
428 syscall_('mount', $_->{real_mntpoint}, $_->{fs_type}, c::MS_MGC_VAL()) or log::l(N("mount failed: ") . $!);
429 }
430 }
431 }
432
433 # write the partition table
434 sub write {
435 my ($hd) = @_;
436 $hd->{isDirty} or return;
437 $hd->{readonly} and internal_error("a read-only partition table should not be dirty ($hd->{device})!");
438
439 #- set first primary partition active if no primary partitions are marked as active.
440 if (my @l = @{$hd->{primary}{raw}}) {
441 foreach (@l) {
442 $_->{local_start} = $_->{start};
443 $_->{active} ||= 0;
444 }
445 $l[0]{active} = 0x80 if !any { $_->{active} } @l;
446 }
447
448 #- last chance for verification, this make sure if an error is detected,
449 #- it will never be writed back on partition table.
450 verifyParts($hd);
451
452 $hd->write(0, $hd->{primary}{raw}, $hd->{primary}{info}) or die "writing of partition table failed";
453
454 #- should be fixed but a extended exist with no real extended partition, that blanks mbr!
455 if (arch() !~ /^sparc/) {
456 foreach (@{$hd->{extended}}) {
457 # in case of extended partitions, the start sector must be local to the partition
458 $_->{normal}{local_start} = $_->{normal}{start} - $_->{start};
459 $_->{extended} and $_->{extended}{local_start} = $_->{extended}{start} - $hd->{primary}{extended}{start};
460
461 $hd->write($_->{start}, $_->{raw}) or die "writing of partition table failed";
462 }
463 }
464 $hd->{isDirty} = 0;
465
466 if (my $tell_kernel = delete $hd->{will_tell_kernel}) {
467 if (fs::type::is_dmraid($hd)) {
468 fs::dmraid::call_dmraid('-an');
469 fs::dmraid::call_dmraid('-ay');
470 } else {
471 tell_kernel($hd, $tell_kernel);
472 }
473 }
474 # get major/minor again after writing the partition table so that we got them for dynamic devices
475 # (eg: for SCSI like devices with kernel-2.6.28+):
476 fs::get_major_minor([ get_normal_parts($hd) ]);
477 }
478
479 sub active {
480 my ($hd, $part) = @_;
481
482 $_->{active} = 0 foreach @{$hd->{primary}{normal}};
483 $part->{active} = 0x80;
484 $hd->{isDirty} = 1;
485 }
486
487
488 # remove a normal partition from hard disk drive hd
489 sub remove {
490 my ($hd, $part) = @_;
491 my $i;
492
493 #- first search it in the primary partitions
494 $i = 0; foreach (@{$hd->{primary}{normal}}) {
495 if ($_ eq $part) {
496 will_tell_kernel($hd, del => $_);
497
498 splice(@{$hd->{primary}{normal}}, $i, 1);
499 %$_ = (); #- blank it
500
501 $hd->raw_removed($hd->{primary}{raw});
502 return 1;
503 }
504 $i++;
505 }
506
507 my ($first, $second, $third) = map { $_->{normal} } @{$hd->{extended} || []};
508 if ($third && $first eq $part) {
509 die "Cannot handle removing hda5 when hda6 is not the second partition" if $second->{start} > $third->{start};
510 }
511
512 #- otherwise search it in extended partitions
513 foreach (@{$hd->{extended} || []}) {
514 $_->{normal} eq $part or next;
515
516 delete $_->{normal}; #- remove it
517 remove_empty_extended($hd);
518 assign_device_numbers($hd);
519
520 will_tell_kernel($hd, del => $part);
521 return 1;
522 }
523 0;
524 }
525
526 # create of partition at starting at `start', of size `size' and of type `pt_type' (nice comment, uh?)
527 sub add_primary {
528 my ($hd, $part) = @_;
529
530 {
531 local $hd->{primary}{normal}; #- save it to fake an addition of $part, that way add_primary do not modify $hd if it fails
532 push @{$hd->{primary}{normal}}, $part;
533 adjust_main_extended($hd); #- verify
534 $hd->raw_add($hd->{primary}{raw}, $part);
535 }
536 push @{$hd->{primary}{normal}}, $part; #- really do it
537 }
538
539 sub add_extended {
540 arch() =~ /^sparc|ppc/ and die N("Extended partition not supported on this platform");
541
542 my ($hd, $part, $extended_type) = @_;
543 $extended_type =~ s/Extended_?//;
544
545 my $e = $hd->{primary}{extended};
546
547 if ($e && !verifyInside($part, $e)) {
548 #-die "sorry, cannot add outside the main extended partition" unless $::unsafe;
549 my $end = $e->{start} + $e->{size};
550 my $start = min($e->{start}, $part->{start});
551 $end = max($end, $part->{start} + $part->{size}) - $start;
552
553 { #- faking a resizing of the main extended partition to test for problems
554 local $e->{start} = $start;
555 local $e->{size} = $end - $start;
556 eval { verifyPrimary($hd->{primary}) };
557 $@ and die
558 N("You have a hole in your partition table but I cannot use it.
559 The only solution is to move your primary partitions to have the hole next to the extended partitions.");
560 }
561 }
562
563 if ($e && $part->{start} < $e->{start}) {
564 my $l = first(@{$hd->{extended}});
565
566 #- the first is a special case, must recompute its real size
567 $l->{start} = round_down($l->{normal}{start} - 1, $hd->cylinder_size);
568 $l->{size} = $l->{normal}{start} + $l->{normal}{size} - $l->{start};
569 my $ext = { %$l };
570 unshift @{$hd->{extended}}, { pt_type => 5, raw => [ $part, $ext, {}, {} ], normal => $part, extended => $ext };
571 #- size will be autocalculated :)
572 } else {
573 my ($ext, $ext_size) = is_empty_array_ref($hd->{extended}) ?
574 ($hd->{primary}, -1) : #- -1 size will be computed by adjust_main_extended
575 (top(@{$hd->{extended}}), $part->{size});
576 my %ext = (pt_type => $extended_type || 5, start => $part->{start}, size => $ext_size);
577
578 $hd->raw_add($ext->{raw}, \%ext);
579 $ext->{extended} = \%ext;
580 push @{$hd->{extended}}, { %ext, raw => [ $part, {}, {}, {} ], normal => $part };
581 }
582 $part->{start}++; $part->{size}--; #- let it start after the extended partition sector
583 adjustStartAndEnd($hd, $part);
584
585 adjust_main_extended($hd);
586 }
587
588 sub add {
589 my ($hd, $part, $b_primaryOrExtended, $b_forceNoAdjust) = @_;
590
591 get_normal_parts($hd) >= ($hd->{device} =~ /^rd/ ? 7 : $hd->{device} =~ /^(ida|cciss|ataraid)/ ? 15 : 63) and cdie "maximum number of partitions handled by linux reached";
592
593 set_isFormatted($part, 0);
594 put_in_hash($part, hd2minimal_part($hd));
595 $part->{start} ||= 1 if arch() !~ /^sparc/; #- starting at sector 0 is not allowed
596 adjustStartAndEnd($hd, $part) unless $b_forceNoAdjust;
597
598 my $nb_primaries = $hd->{device} =~ /^rd/ ? 3 : 1;
599
600 if (arch() =~ /^sparc|ppc/ ||
601 $b_primaryOrExtended eq 'Primary' ||
602 $b_primaryOrExtended !~ /Extended/ && @{$hd->{primary}{normal} || []} < $nb_primaries) {
603 eval { add_primary($hd, $part) };
604 goto success if !$@;
605 }
606 if ($hd->hasExtended) {
607 eval { add_extended($hd, $part, $b_primaryOrExtended) };
608 goto success if !$@;
609 }
610 {
611 add_primary($hd, $part);
612 }
613 success:
614 assign_device_numbers($hd);
615 will_tell_kernel($hd, add => $part);
616 }
617
618 # search for the next partition
619 sub next {
620 my ($hd, $part) = @_;
621
622 first(
623 sort { $a->{start} <=> $b->{start} }
624 grep { $_->{start} >= $part->{start} + $part->{size} }
625 get_normal_parts($hd)
626 );
627 }
628 sub next_start {
629 my ($hd, $part) = @_;
630 my $next = &next($hd, $part);
631 $next ? $next->{start} : $hd->last_usable_sector;
632 }
633
634 1;

  ViewVC Help
Powered by ViewVC 1.1.30