source: MondoRescue/branches/3.0/mindi/parted2fdisk.pl@ 3508

Last change on this file since 3508 was 3360, checked in by Bruno Cornec, 9 years ago

Backports from 3.2 (rev 3336-3359):

  • Improve kernel 3.14+ detection for initramfs
  • Fix installation of parted2fdisk under rootfs by removing useless -s option of install
  • Remove usage of internal function basename in parted2fdisk use File::Basename instead
  • Property svn:keywords set to Id
File size: 16.8 KB
Line 
1#!/usr/bin/perl -w
2#
3# $Id: parted2fdisk.pl 3360 2015-03-07 13:41:11Z bruno $
4#
5# parted2fdisk: fdisk like interface for parted
6# [developed for mindi/mondo http://www.mondorescue.org]
7#
8# Aims to be architecture independant (i386/ia64)
9# Tested on ia64 with RHAS 2.1 - Mandrake 9.0 - RHEL 3.0 - SLES 10
10#
11# Copyright B. Cornec 2000-2015
12# Provided under the GPL v2
13
14use strict;
15use File::Basename;
16
17
18=pod
19
20=head1 NAME
21
22parted2fdisk is a fdisk like command using parted internally.
23
24=head1 DESCRIPTION
25
26parted2fdisk behaves like the fdisk command, but dialog internally with parted in order to manipulate partition tables, which allow it to support GPT partition format as well as MBR, contrary to fdisk. It aims at providing compatible external interface with fdisk. Developed initialy for ia64 Linux, it is also useful now on x86 systems using GPT partition format (for large HDDs).
27
28=head1 SYNOPSIS
29
30parted2fdisk -s partition
31parted2fdisk -l device
32parted2fdisk [-n] device
33
34=head1 OPTIONS
35
36=over 4
37
38=item B<-s>
39
40Print the size (in blocks) of the given partition.
41
42=item B<-n>
43
44Fake mode. Doesn't pass the commands just simulate.
45
46=item B<-l>
47
48List the partition tables for the specified device and then exit.
49
50=item B<no option>
51
52Allow the creation and manipulation of partition tables.
53
54=back
55
56=head1 ARGUMENTS
57
58=over 4
59
60=item B<partition>
61
62partition device file (only used with -s option).
63
64=item B<device>
65
66device file to work on.
67
68=back
69
70=head1 WEB SITES
71
72The main Web site of the project is available at L<http://www.mondorescue.org>. Bug reports should be filled using the trac instance of the project at L<http://trac.mondorescue.org/>.
73
74=head1 USER MAILING LIST
75
76For community exchanges around MondoRescue please use the list L<http://sourceforge.net/mailarchive/forum.php?forum_name=mondo-devel>
77
78=head1 AUTHORS
79
80The MondoRescue team lead by Bruno Cornec L<mailto:bruno@mondorescue.org>.
81
82=head1 COPYRIGHT
83
84MondoRescue is distributed under the GPL v2.0 license or later,
85described in the file C<COPYING> included with the distribution.
86
87=cut
88
89
90$ENV{LANG} = "C";
91$ENV{LANGUAGE} = "C";
92$ENV{LC_ALL} = "C";
93
94# Log
95my $flog = "/var/log/parted2fdisk.log";
96open(FLOG, "> $flog") || die "Unable to open $flog";
97
98my $fdisk = "/sbin/fdisk";
99$fdisk = "/usr/sbin/fdisk" if (not -x "/sbin/fdisk");
100my $parted = "/sbin/parted";
101$parted = "/usr/sbin/parted" if (not -x "/sbin/parted");
102
103my $i;
104my $l;
105my $part;
106my $wpart;
107my $start = "";
108my $end = "";
109my $cylstart;
110my $cylend;
111my %start;
112my %end;
113my %type;
114my $arch;
115my $fake = 0;
116my $mega = 1048576;
117
118# Immediate flushing to avoids read error from mondorestore in log files
119$| = 1;
120
121# Determine on which arch we're running
122if (defined ($ENV{ARCH})) {
123 $arch = $ENV{ARCH};
124} else {
125 $arch = `uname -m`;
126 chomp($arch);
127}
128
129#
130# Looking for fdisk
131#
132$fdisk = is_lsb($fdisk);
133#
134# We always use fdisk except on ia64 with GPT types of
135# partition tables where we need parted
136# All should return fdisk like format so that callers
137# think they have called fdisk directly
138#
139my $un;
140my $type;
141my $args = "";
142my $device = "";
143my $endmax = "";
144
145if ($#ARGV < 0) {
146 printf FLOG "No arguments given exiting ...\n";
147 mysyn();
148}
149
150my %pid = ( "FAT" => "6",
151 "fat32" => "b",
152 "fat16" => "e",
153 "ext2" => "83",
154 "ext3" => "83",
155 "ext4" => "83",
156 "xfs" => "83",
157 "btrfs" => "83",
158 "reiserfs" => "83",
159 "linux-swap" => "82",
160 "lvm" => "8e",
161 "raid" => "fd",
162 "" => "",
163 );
164my %pnum;
165
166# Reverse table of pid
167while (($i,$l) = each %pid) {
168 next if ($i eq "ext2");
169 $pnum{$l} = $i;
170}
171
172foreach $i (@ARGV) {
173 # We support at most one option and one device
174 print FLOG "Parameter found : $i\n";
175 if ($i =~ /^\/dev\//) {
176 $device = $i;
177 next;
178 } elsif ($i =~ /^-/) {
179 $args = $i;
180 next;
181 } else {
182 mysyn();
183 }
184}
185
186if (($args ne "") and ($device eq "")) {
187 mysyn();
188}
189
190# -s takes a partition as arg
191if ($args =~ /-s/) {
192 $wpart = $device;
193 $device =~ s/[0-9]+$//;
194}
195
196if ($args =~ /-n/) {
197 print FLOG "Fake mode. Nothing will be really done\n";
198 $fake = 1;
199}
200
201print FLOG "Called with device $device and arg $args\n";
202
203if ($arch =~ /^ia64/) {
204 # Check partition table type
205 print FLOG "We're on ia64 ...\n";
206 $parted = is_lsb($parted);
207 $type = which_type($device);
208 if ($type ne "msdos") {
209 print FLOG "Not an msdos type of disk label\n";
210 if ($args =~ /-l/) {
211 fdisk_list($device,undef,\%start,\%end, 1);
212 } elsif ($args =~ /-s/) {
213 fdisk_list($device,$wpart,\%start,\%end, 1);
214 } elsif (($args =~ /-/) and ($fake == 0)) {
215 printf FLOG "Option not supported ($args) ...\n";
216 printf FLOG "Please report to the author\n";
217 mysyn();
218 } else {
219 # Read fdisk orders on stdin and pass them to parted
220 # on the command line as parted doesn't read on stdin
221 print FLOG "Translating fdisk command to parted\n";
222 while ($i = <STDIN>) {
223 if ($i =~ /^p$/) {
224 fdisk_list($device,undef,\%start,\%end, 1);
225 print "command (m for help) send back to fake fdisk for mondorestore\n";
226 } elsif ($i =~ /^n$/) {
227 fdisk_list($device,undef,\%start,\%end, 0);
228 if ($type ne "gpt") {
229 print FLOG "Forcing GPT type of disk label\n";
230 print FLOG "mklabel gpt\n";
231 system "$parted -s $device mklabel gpt\n" if ($fake == 0);
232 $type = "gpt";
233 }
234 $l = <STDIN>;
235 if (not (defined $l)) {
236 print FLOG "no primary/extended arg given for creation... assuming primary\n";
237 $l = "p";
238 }
239 chomp($l);
240 $part = <STDIN>;
241 if ((not (defined $part)) || ($part eq "")) {
242 print FLOG "no partition given for creation... skipping\n";
243 next;
244 }
245 chomp($part);
246 $cylstart = <STDIN>;
247 chomp($cylstart);
248 if ((not (defined $cylstart)) || ($cylstart eq "")) {
249 if (defined $start{$part-1}) {
250 # in MB => cyl
251 $cylstart = sprintf("%d",$end{$part-1}*$mega/$un + 1);
252 print FLOG "no start cyl given for creation... assuming the following $cylstart\n";
253 } else {
254 print FLOG "no start cyl given for creation... assuming the following 1\n";
255 $cylstart = 1;
256 }
257 }
258 $cylstart = 1 if ($cylstart < 1);
259 print FLOG "start cyl : $cylstart\n";
260 $un = get_un($device, "", 0);
261 # parted needs MB
262 if ($cylstart == 1) {
263 $start = 0.01;
264 } else {
265 $start = $cylstart* $un / $mega + 0.001;
266 }
267 # this is a size in B/KB/MB/GB
268
269 $endmax = get_max($device);
270 $cylend = <STDIN>;
271 chomp($cylend);
272 if ((not (defined $cylend)) || ($cylend eq "")) {
273 print FLOG "no end cyl given for creation... assuming full disk)\n";
274 $cylend = $endmax;
275 }
276 # Handles end syntaxes (+, K, M, ...)
277 # to give cylinders
278 if ($cylend =~ /^\+/) {
279 $cylend =~ s/^\+//;
280 # Handles suffixes; return bytes
281 $cylend = decode_Bsuf($cylend,1);
282 # This gives the number of cyl
283 $cylend /= $un;
284 $cylend = sprintf("%d",$cylend);
285 $cylend += $cylstart - 0.001;
286 # We now have the end cyl
287 }
288 $cylend = $endmax if ($cylend > $endmax);
289 print FLOG "end cyl : $cylend\n";
290 # parted needs MB
291 $end = $cylend * $un / $mega;
292 print FLOG "n $l $part $cylstart $cylend => mkpart primary $start $end\n";
293 system "$parted -s $device mkpart primary ext2 $start $end\n" if ($fake == 0);
294 print "command (m for help) send back to fake fdisk for mondorestore\n";
295 } elsif ($i =~ /^d$/) {
296 $part = <STDIN>;
297 if (not (defined $part)) {
298 print FLOG "no partition given for deletion... skipping\n";
299 next;
300 }
301 chomp($part);
302 print FLOG "d $part => rm $part\n";
303 system "$parted -s $device rm $part\n" if ($fake == 0);
304 get_parted($device,undef,\%start,\%end,undef);
305 print "command (m for help) send back to fake fdisk for mondorestore\n";
306 } elsif ($i =~ /^w$/) {
307 print FLOG "w => quit\n";
308 } elsif ($i =~ /^t$/) {
309 $part = <STDIN>;
310 if (not (defined $part)) {
311 print FLOG "no partition given for tagging... skipping\n";
312 next;
313 }
314 chomp($part);
315 # If no partition number given it's 1, and we received the type
316 if ($part !~ /\d+/) {
317 $l = $part;
318 $part = 1
319 } else {
320 $l = <STDIN>;
321 }
322 if (not (defined $l)) {
323 print FLOG "no type given for tagging partition $part... skipping\n";
324 next;
325 }
326 chomp($l);
327 if (not (defined $pnum{$l})) {
328 print FLOG "no partition number given for $l... please report to the author\n";
329 next;
330 }
331
332 if ($pnum{$l} eq "lvm") {
333 # In that case this is a flag set, not a mkfs
334 print FLOG "t $part $l => set $part $pnum{$l} on\n";
335 system "$parted -s $device set $part $pnum{$l} on\n" if ($fake == 0);
336 } else {
337 print FLOG "t $part $l => mkfs $part $pnum{$l}\n";
338 system "$parted -s $device mkfs $part $pnum{$l}\n" if ($fake == 0);
339 }
340 print "command (m for help) send back to fake fdisk for mondorestore\n";
341 } elsif ($i =~ /^a$/) {
342 $part = <STDIN>;
343 if (not (defined $part)) {
344 print FLOG "no partition given for tagging... skipping\n";
345 next;
346 }
347 chomp($part);
348
349 # Partition shouldn't be negative or null. Then take the first one.
350 $part = 1 if ($part le 0);
351
352 print FLOG "a $part => set $part boot on\n";
353 system "$parted -s $device set $part boot on\n" if ($fake == 0);
354 print "command (m for help) send back to fake fdisk for mondorestore\n";
355 } elsif ($i =~ /^q$/) {
356 print FLOG "q => quit\n";
357 } else {
358 print FLOG "Unknown command: $i\n";
359 print "command (m for help) send back to fake fdisk for mondorestore\n";
360 next;
361 }
362
363 }
364 }
365 myexit(0);
366 }
367}
368
369#
370# Else everything is for fdisk
371#
372# Print only mode
373print FLOG "Passing everything to the real fdisk\n";
374my $fargs = join(@ARGV);
375
376if ($args =~ /^-/) {
377 # -l or -s
378 open (FDISK, "$fdisk $fargs 2>/dev/null |") || die "Unable to read from $fdisk";
379 while (<FDISK>) {
380 print;
381 }
382 close(FDISK);
383} else {
384 # Modification mode
385 open (FDISK, "| $fdisk $fargs 2>/dev/null") || die "Unable to modify through $fdisk";
386 while (<STDIN>) {
387 print FDISK;
388 }
389 close(FDISK);
390 close(STDIN);
391}
392myexit(0);
393
394
395# Is your system LSB ?
396sub is_lsb {
397
398my $cmd = shift;
399my $basename = basename($cmd);
400
401if (not (-x $cmd)) {
402 print FLOG "Your system is not LSB/mondo compliant: $basename was not found as $cmd\n";
403 print FLOG "Searching elswhere...";
404 foreach $i (split(':',$ENV{PATH})) {
405 if (-x "$i/$basename") {
406 $cmd = "$i/$basename";
407 print FLOG "Found $cmd, using it !\n";
408 last;
409 }
410 }
411 if (not (-x $cmd)) {
412 print FLOG "Your system doesn't provide $basename in the PATH\n";
413 print FLOG "Please correct it before relaunching\n";
414 myexit(-1);
415 }
416}
417return($cmd);
418}
419
420sub fdisk_list {
421
422my $device = shift;
423my $wpart = shift;
424my $start = shift;
425my $end = shift;
426my $verbose = shift;
427
428my $un;
429my $endmax;
430my $d;
431my $n;
432
433my %cmt = ( "FAT" => "FAT",
434 "ext2" => "Linux",
435 "ext3" => "Linux",
436 "ext4" => "Linux",
437 "xfs" => "Linux",
438 "reiserfs" => "Linux",
439 "linux-swap" => "Linux swap",
440 "lvm" => "Linux LVM",
441 "raid" => "RAID Linux auto",
442 "fat16" => "fat16",
443 "fat32" => "fat32",
444 "" => "Linux",
445);
446
447my $part;
448my $mstart;
449my $mend;
450my $length;
451my $pid;
452my $cmt;
453format FLOG1 =
454@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
455$part, $mstart, $mend, $length, $pid, $cmt
456.
457format FLOG2 =
458@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
459$part,
460 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
461 $mstart, $mend, $length, $pid, $cmt
462.
463format STDOUT1 =
464@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
465$part, $mstart, $mend, $length, $pid, $cmt
466.
467format STDOUT2 =
468@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
469$part,
470 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
471 $mstart, $mend, $length, $pid, $cmt
472.
473# Device Boot Start End Blocks Id System
474#/dev/hda1 1 77579 39099374+ ee EFI GPT
475
476
477#
478# Keep Fdisk headers
479#
480# this will return bytes
481$un = get_un ($device,$wpart,$verbose);
482
483$endmax = get_max($device);
484
485# This will return MB
486get_parted($device,$start,$end,\%type);
487
488while (($n,$d) = each %type) {
489 # Print infos fdisk like
490 $part = ${device}.$n;
491 # start and end are in cylinder in fdisk format
492 # so return in MB * 1MB / what represents 1 cyl in B
493 $mstart = sprintf("%d",$$start{$n}*$mega/$un);
494 $mstart = 1 if ($mstart < 1);
495 $mstart = $endmax if ($mstart > $endmax);
496 $mend = sprintf("%d",$$end{$n}*$mega/$un - 1);
497 $mend = $endmax if ($mend > $endmax);
498 $mend = 1 if ($mend < 1);
499 # length is in 1K blocks
500 $length = sprintf("%d",($mend-$mstart+1)*$un/1024);
501 $pid = $pid{$type{$n}};
502 $cmt = $cmt{$type{$n}};
503 #print FLOG "$part - $mstart - $mend - $length\n";
504
505 if ($verbose == 1) {
506 if (not (defined $wpart)) {
507 if (length($part) > 13) {
508 open(STDOUT2,">&STDOUT") || die "Unable to open STDOUT2";
509 select(STDOUT2);
510 write;
511 open(FLOG2,">&FLOG") || die "Unable to open FLOG2";
512 select(FLOG2);
513 write;
514 select(STDOUT);
515 close(FLOG2);
516 close(STDOUT2);
517 } else {
518 open(STDOUT1,">&STDOUT") || die "Unable to open STDOUT1";
519 select(STDOUT1);
520 write;
521 open(FLOG1,">&FLOG") || die "Unable to open FLOG1";
522 select(FLOG1);
523 write;
524 select(STDOUT);
525 close(FLOG1);
526 close(STDOUT1);
527 }
528 } else {
529 # manage the -s option of fdisk here
530 print "$length\n" if ($part eq $wpart);
531 print FLOG "$part has $length KBytes\n" if ($part eq $wpart);
532 }
533 }
534}
535close(FDISK);
536close(PARTED);
537}
538
539#
540# Get max size from fdisk
541#
542sub get_max {
543
544my $device = shift;
545my $max = 0;
546my $foo;
547
548open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
549while (<FDISK>) {
550 if ($_ =~ /heads/) {
551 chomp;
552 $max = $_;
553 $max =~ s/.* ([0-9]+) cylinders/$1/;
554 }
555}
556close(FDISK);
557print FLOG "get_max returns $max\n";
558return($max);
559}
560
561#
562# Get units from fdisk (cylinder size)
563#
564sub get_un {
565
566my $device = shift;
567my $wpart = shift;
568my $verbose = shift;
569my $un = 0;
570my $foo;
571
572open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
573while (<FDISK>) {
574 print if (($_ !~ /^\/dev\//) and (not (defined $wpart)) and ($verbose == 1));
575 if ($_ =~ /^Units/) {
576 ($foo, $un , $foo) = split /=/;
577 $un =~ s/[A-z\s=]//g;
578 $un = eval($un);
579 }
580}
581close(FDISK);
582print FLOG "get_un returns $un\n";
583return($un);
584}
585
586#
587# Parted gives info in MB
588# (depending on versions - 1.6.25.1 provides suffixes)
589#
590sub get_parted {
591
592my $device = shift;
593my $start = shift;
594my $end = shift;
595my $type = shift;
596my $void;
597my $d;
598my $n;
599my $ret;
600my $mode;
601my $size;
602my $unit;
603
604open (PARTED, "$parted -v |") || die "Unable to read from $parted";
605$d = <PARTED>;
606print FLOG "$d";
607close(PARTED);
608
609open (PARTED, "$parted -s $device print |") || die "Unable to read from $parted";
610# Skip 3 first lines
611$d = <PARTED>;
612$d = <PARTED>;
613$d = <PARTED>;
614
615# depending on parted version, information given change:
616if ($d =~ /\bSize\b/) {
617 # SLES 10 parted >= 1.6.25
618 $mode=1;
619} else {
620 # RHEL 3 parted 1.6.3
621 # RHEL 4 parted 1.6.19
622 $mode=0;
623}
624print FLOG "mode: $mode\n";
625print FLOG "Got from parted: \n";
626print FLOG "Minor Start End Filesystem\n";
627# Get info from each partition line
628while (($n,$d) = split(/\s/, <PARTED>,2)) {
629 chomp($d);
630 next if ($n !~ /^[1-9]/);
631 $d =~ s/^\s*//;
632 $d =~ s/\s+/ /g;
633 if ($mode == 0) {
634 ($$start{$n},$$end{$n},$$type{$n},$void) = split(/ /,$d);
635 $unit = 1;
636 } elsif ($mode == 1) {
637 ($$start{$n},$$end{$n},$size,$$type{$n},$void) = split(/ /,$d);
638 $unit = $mega;
639 } else {
640 die "Undefined mode $mode";
641 }
642 $$start{$n} = "" if (not defined $$start{$n});
643 $$end{$n} = "" if (not defined $$end{$n});
644 $$type{$n} = "" if (not defined $$type{$n});
645 # Handles potential suffixes in latest parted version. Return MB
646 $ret = decode_Bsuf($$start{$n},$unit);
647 $$start{$n} = $ret;
648 $ret = decode_Bsuf($$end{$n},$unit);
649 $$end{$n} = $ret;
650 print FLOG "$n $$start{$n} $$end{$n} $$type{$n}\n";
651}
652close(PARTED);
653}
654
655sub decode_Bsuf {
656
657my $size = shift;
658my $unit = shift;
659my $ret = 0;
660
661#print FLOG "decode_Bsuf input: $size / $unit ";
662if ($size =~ /K[B]*$/i) {
663 $size =~ s/K[B]*$//i;
664 $size *= 1024;
665} elsif ($size =~ /M[B]*$/i) {
666 $size =~ s/M[B]*$//i;
667 $size *= 1048576;
668} elsif ($size =~ /G[B]*$/i) {
669 $size =~ s/G[B]*$//i;
670 $size *= 1073741824;
671} elsif ($size =~ /T[B]*$/i) {
672 $size =~ s/T[B]*$//i;
673 $size *= 1099511627776;
674} else {
675 # Nothing to do
676}
677$ret = $size / $unit;
678#print FLOG " - output : $size => $ret\n";
679return($ret);
680}
681
682sub myexit {
683
684my $val=shift;
685
686close(FLOG);
687exit($val);
688}
689
690sub which_type {
691
692my $device = shift;
693my $type = "";
694
695open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
696while (<FDISK>) {
697 if ($_ =~ /EFI GPT/) {
698 $type= "gpt";
699 print FLOG "Found a GPT partition format\n";
700 last;
701 }
702}
703close(FDISK);
704open (PARTED, "$parted -s $device print|") || die "Unable to read from $fdisk";
705while (<PARTED>) {
706 if ($_ =~ /Disk label type: msdos/) {
707 $type= "msdos";
708 print FLOG "Found a msdos partition format\n";
709 last;
710 }
711}
712close(FDISK);
713return ($type);
714}
715
716sub mysyn {
717 print "Syntax: $0 [-l] device | [-s] partition\n";
718 myexit(-1);
719}
Note: See TracBrowser for help on using the repository browser.