source: MondoRescue/branches/3.2/mindi/parted2fdisk.pl@ 3343

Last change on this file since 3343 was 3343, checked in by Bruno Cornec, 9 years ago
  • parted2fdisk now works also on x86 machines and just check fdisk version to replace it when too old to support GPT. Is now a full

replacement of fdisk usage in mondo

  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1#!/usr/bin/perl -w
2#
3# $Id: parted2fdisk.pl 3343 2015-02-13 19:27:10Z 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 $fake = 0;
115my $mega = 1048576;
116
117# Immediate flushing to avoids read error from mondorestore in log files
118$| = 1;
119
120#
121# Looking for fdisk
122#
123$fdisk = is_lsb($fdisk);
124#
125# We always use fdisk except with GPT types of
126# partition tables where we need parted
127# All should return fdisk like format so that callers
128# think they have called fdisk directly
129#
130my $un;
131my $type;
132my $args = "";
133my $device = "";
134my $endmax = "";
135
136if ($#ARGV < 0) {
137 printf FLOG "No arguments given exiting ...\n";
138 mysyn();
139}
140
141my %pid = ( "FAT" => "6",
142 "fat32" => "b",
143 "fat16" => "e",
144 "ext2" => "83",
145 "ext3" => "83",
146 "ext4" => "83",
147 "xfs" => "83",
148 "btrfs" => "83",
149 "reiserfs" => "83",
150 "linux-swap" => "82",
151 "lvm" => "8e",
152 "raid" => "fd",
153 "" => "",
154 );
155my %pnum;
156
157# Reverse table of pid
158while (($i,$l) = each %pid) {
159 next if ($i eq "ext2");
160 $pnum{$l} = $i;
161}
162
163foreach $i (@ARGV) {
164 # We support at most one option and one device
165 print FLOG "Parameter found : $i\n";
166 if ($i =~ /^\/dev\//) {
167 $device = $i;
168 next;
169 } elsif ($i =~ /^-/) {
170 $args = $i;
171 next;
172 } else {
173 mysyn();
174 }
175}
176
177if (($args ne "") and ($device eq "")) {
178 mysyn();
179}
180
181# -s takes a partition as arg
182if ($args =~ /-s/) {
183 $wpart = $device;
184 $device =~ s/[0-9]+$//;
185}
186
187if ($args =~ /-n/) {
188 print FLOG "Fake mode. Nothing will be really done\n";
189 $fake = 1;
190}
191
192print FLOG "Called with device $device and arg $args\n";
193
194# util-linux/fdisk version
195open(CMD,"$fdisk -v |") || die "Unable to execute $fdisk";
196my $version = <CMD>;
197close(CMD);
198chomp($version);
199$version =~ s/[^0-9\.]*([0-9\.]+)[\)]$/$1/;
200my ($v,$maj,$min) = split(/\./,$version);
201
202if (($v == 1) || (($v == 2) && ($maj < 22))) {
203 # Check partition table type
204 print FLOG "We use an old fdisk, activating replacement code...\n";
205 $parted = is_lsb($parted);
206 $type = which_type($device);
207 if ($type ne "msdos") {
208 print FLOG "Not an msdos type of disk label\n";
209 if ($args =~ /-l/) {
210 fdisk_list($device,undef,\%start,\%end, 1);
211 } elsif ($args =~ /-s/) {
212 fdisk_list($device,$wpart,\%start,\%end, 1);
213 } elsif (($args =~ /-/) and ($fake == 0)) {
214 printf FLOG "Option not supported ($args) ...\n";
215 printf FLOG "Please report to the author\n";
216 mysyn();
217 } else {
218 # Read fdisk orders on stdin and pass them to parted
219 # on the command line as parted doesn't read on stdin
220 print FLOG "Translating fdisk command to parted\n";
221 while ($i = <STDIN>) {
222 if ($i =~ /^p$/) {
223 fdisk_list($device,undef,\%start,\%end, 1);
224 print "command (m for help) send back to fake fdisk for mondorestore\n";
225 } elsif ($i =~ /^n$/) {
226 fdisk_list($device,undef,\%start,\%end, 0);
227 if ($type ne "gpt") {
228 print FLOG "Forcing GPT type of disk label\n";
229 print FLOG "mklabel gpt\n";
230 system "$parted -s $device mklabel gpt\n" if ($fake == 0);
231 $type = "gpt";
232 }
233 $l = <STDIN>;
234 if (not (defined $l)) {
235 print FLOG "no primary/extended arg given for creation... assuming primary\n";
236 $l = "p";
237 }
238 chomp($l);
239 $part = <STDIN>;
240 if ((not (defined $part)) || ($part eq "")) {
241 print FLOG "no partition given for creation... skipping\n";
242 next;
243 }
244 chomp($part);
245 $cylstart = <STDIN>;
246 chomp($cylstart);
247 if ((not (defined $cylstart)) || ($cylstart eq "")) {
248 if (defined $start{$part-1}) {
249 # in MB => cyl
250 $cylstart = sprintf("%d",$end{$part-1}*$mega/$un + 1);
251 print FLOG "no start cyl given for creation... assuming the following $cylstart\n";
252 } else {
253 print FLOG "no start cyl given for creation... assuming the following 1\n";
254 $cylstart = 1;
255 }
256 }
257 $cylstart = 1 if ($cylstart < 1);
258 print FLOG "start cyl : $cylstart\n";
259 $un = get_un($device, "", 0);
260 # parted needs MB
261 if ($cylstart == 1) {
262 $start = 0.01;
263 } else {
264 $start = $cylstart* $un / $mega + 0.001;
265 }
266 # this is a size in B/KB/MB/GB
267
268 $endmax = get_max($device);
269 $cylend = <STDIN>;
270 chomp($cylend);
271 if ((not (defined $cylend)) || ($cylend eq "")) {
272 print FLOG "no end cyl given for creation... assuming full disk)\n";
273 $cylend = $endmax;
274 }
275 # Handles end syntaxes (+, K, M, ...)
276 # to give cylinders
277 if ($cylend =~ /^\+/) {
278 $cylend =~ s/^\+//;
279 # Handles suffixes; return bytes
280 $cylend = decode_Bsuf($cylend,1);
281 # This gives the number of cyl
282 $cylend /= $un;
283 $cylend = sprintf("%d",$cylend);
284 $cylend += $cylstart - 0.001;
285 # We now have the end cyl
286 }
287 $cylend = $endmax if ($cylend > $endmax);
288 print FLOG "end cyl : $cylend\n";
289 # parted needs MB
290 $end = $cylend * $un / $mega;
291 print FLOG "n $l $part $cylstart $cylend => mkpart primary $start $end\n";
292 system "$parted -s $device mkpart primary ext2 $start $end\n" if ($fake == 0);
293 print "command (m for help) send back to fake fdisk for mondorestore\n";
294 } elsif ($i =~ /^d$/) {
295 $part = <STDIN>;
296 if (not (defined $part)) {
297 print FLOG "no partition given for deletion... skipping\n";
298 next;
299 }
300 chomp($part);
301 print FLOG "d $part => rm $part\n";
302 system "$parted -s $device rm $part\n" if ($fake == 0);
303 get_parted($device,undef,\%start,\%end,undef);
304 print "command (m for help) send back to fake fdisk for mondorestore\n";
305 } elsif ($i =~ /^w$/) {
306 print FLOG "w => quit\n";
307 } elsif ($i =~ /^t$/) {
308 $part = <STDIN>;
309 if (not (defined $part)) {
310 print FLOG "no partition given for tagging... skipping\n";
311 next;
312 }
313 chomp($part);
314 # If no partition number given it's 1, and we received the type
315 if ($part !~ /\d+/) {
316 $l = $part;
317 $part = 1
318 } else {
319 $l = <STDIN>;
320 }
321 if (not (defined $l)) {
322 print FLOG "no type given for tagging partition $part... skipping\n";
323 next;
324 }
325 chomp($l);
326 if (not (defined $pnum{$l})) {
327 print FLOG "no partition number given for $l... please report to the author\n";
328 next;
329 }
330
331 if ($pnum{$l} eq "lvm") {
332 # In that case this is a flag set, not a mkfs
333 print FLOG "t $part $l => set $part $pnum{$l} on\n";
334 system "$parted -s $device set $part $pnum{$l} on\n" if ($fake == 0);
335 } else {
336 print FLOG "t $part $l => mkfs $part $pnum{$l}\n";
337 system "$parted -s $device mkfs $part $pnum{$l}\n" if ($fake == 0);
338 }
339 print "command (m for help) send back to fake fdisk for mondorestore\n";
340 } elsif ($i =~ /^a$/) {
341 $part = <STDIN>;
342 if (not (defined $part)) {
343 print FLOG "no partition given for tagging... skipping\n";
344 next;
345 }
346 chomp($part);
347
348 # Partition shouldn't be negative or null. Then take the first one.
349 $part = 1 if ($part le 0);
350
351 print FLOG "a $part => set $part boot on\n";
352 system "$parted -s $device set $part boot on\n" if ($fake == 0);
353 print "command (m for help) send back to fake fdisk for mondorestore\n";
354 } elsif ($i =~ /^q$/) {
355 print FLOG "q => quit\n";
356 } else {
357 print FLOG "Unknown command: $i\n";
358 print "command (m for help) send back to fake fdisk for mondorestore\n";
359 next;
360 }
361
362 }
363 }
364 myexit(0);
365 }
366}
367
368#
369# Else everything is for fdisk
370#
371# Print only mode
372print FLOG "Passing everything to the real fdisk\n";
373my $fargs = join(@ARGV);
374
375if ($args =~ /^-/) {
376 # -l or -s
377 open (FDISK, "$fdisk $fargs 2>/dev/null |") || die "Unable to read from $fdisk";
378 while (<FDISK>) {
379 print;
380 }
381 close(FDISK);
382} else {
383 # Modification mode
384 open (FDISK, "| $fdisk $fargs 2>/dev/null") || die "Unable to modify through $fdisk";
385 while (<STDIN>) {
386 print FDISK;
387 }
388 close(FDISK);
389 close(STDIN);
390}
391myexit(0);
392
393
394# Is your system LSB ?
395sub is_lsb {
396
397my $cmd = shift;
398my $basename = basename($cmd);
399
400if (not (-x $cmd)) {
401 print FLOG "Your system is not LSB/mondo compliant: $basename was not found as $cmd\n";
402 print FLOG "Searching elswhere...";
403 foreach $i (split(':',$ENV{PATH})) {
404 if (-x "$i/$basename") {
405 $cmd = "$i/$basename";
406 print FLOG "Found $cmd, using it !\n";
407 last;
408 }
409 }
410 if (not (-x $cmd)) {
411 print FLOG "Your system doesn't provide $basename in the PATH\n";
412 print FLOG "Please correct it before relaunching\n";
413 myexit(-1);
414 }
415}
416return($cmd);
417}
418
419sub fdisk_list {
420
421my $device = shift;
422my $wpart = shift;
423my $start = shift;
424my $end = shift;
425my $verbose = shift;
426
427my $un;
428my $endmax;
429my $d;
430my $n;
431
432my %cmt = ( "FAT" => "FAT",
433 "ext2" => "Linux",
434 "ext3" => "Linux",
435 "ext4" => "Linux",
436 "xfs" => "Linux",
437 "reiserfs" => "Linux",
438 "linux-swap" => "Linux swap",
439 "lvm" => "Linux LVM",
440 "raid" => "RAID Linux auto",
441 "fat16" => "fat16",
442 "fat32" => "fat32",
443 "" => "Linux",
444);
445
446my $part;
447my $mstart;
448my $mend;
449my $length;
450my $pid;
451my $cmt;
452format FLOG1 =
453@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
454$part, $mstart, $mend, $length, $pid, $cmt
455.
456format FLOG2 =
457@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
458$part,
459 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
460 $mstart, $mend, $length, $pid, $cmt
461.
462format STDOUT1 =
463@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
464$part, $mstart, $mend, $length, $pid, $cmt
465.
466format STDOUT2 =
467@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
468$part,
469 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
470 $mstart, $mend, $length, $pid, $cmt
471.
472# Device Boot Start End Blocks Id System
473#/dev/hda1 1 77579 39099374+ ee EFI GPT
474
475
476#
477# Keep Fdisk headers
478#
479# this will return bytes
480$un = get_un ($device,$wpart,$verbose);
481
482$endmax = get_max($device);
483
484# This will return MB
485get_parted ($device,$start,$end,\%type);
486
487while (($n,$d) = each %type) {
488 # Print infos fdisk like
489 $part = ${device}.$n;
490 # start and end are in cylinder in fdisk format
491 # so return in MB * 1MB / what represents 1 cyl in B
492 $mstart = sprintf("%d",$$start{$n}*$mega/$un);
493 $mstart = 1 if ($mstart < 1);
494 $mstart = $endmax if ($mstart > $endmax);
495 $mend = sprintf("%d",$$end{$n}*$mega/$un - 1);
496 $mend = $endmax if ($mend > $endmax);
497 $mend = 1 if ($mend < 1);
498 # length is in 1K blocks
499 $length = sprintf("%d",($mend-$mstart+1)*$un/1024);
500 $pid = $pid{$type{$n}};
501 $cmt = $cmt{$type{$n}};
502 #print FLOG "$part - $mstart - $mend - $length\n";
503
504 if ($verbose == 1) {
505 if (not (defined $wpart)) {
506 if (length($part) > 13) {
507 open(STDOUT2,">&STDOUT") || die "Unable to open STDOUT2";
508 select(STDOUT2);
509 write;
510 open(FLOG2,">&FLOG") || die "Unable to open FLOG2";
511 select(FLOG2);
512 write;
513 select(STDOUT);
514 close(FLOG2);
515 close(STDOUT2);
516 } else {
517 open(STDOUT1,">&STDOUT") || die "Unable to open STDOUT1";
518 select(STDOUT1);
519 write;
520 open(FLOG1,">&FLOG") || die "Unable to open FLOG1";
521 select(FLOG1);
522 write;
523 select(STDOUT);
524 close(FLOG1);
525 close(STDOUT1);
526 }
527 } else {
528 # manage the -s option of fdisk here
529 print "$length\n" if ($part eq $wpart);
530 print FLOG "$part has $length KBytes\n" if ($part eq $wpart);
531 }
532 }
533}
534close(FDISK);
535close(PARTED);
536}
537
538#
539# Get max size from fdisk
540#
541sub get_max {
542
543my $device = shift;
544my $max = 0;
545my $foo;
546
547open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
548while (<FDISK>) {
549 if ($_ =~ /heads/) {
550 chomp;
551 $max = $_;
552 $max =~ s/.* ([0-9]+) cylinders/$1/;
553 }
554}
555close(FDISK);
556print FLOG "get_max returns $max\n";
557return($max);
558}
559
560#
561# Get units from fdisk (cylinder size)
562#
563sub get_un {
564
565my $device = shift;
566my $wpart = shift;
567my $verbose = shift;
568my $un = 0;
569my $foo;
570
571open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
572while (<FDISK>) {
573 print if (($_ !~ /^\/dev\//) and (not (defined $wpart)) and ($verbose == 1));
574 if ($_ =~ /^Units/) {
575 ($foo, $un , $foo) = split /=/;
576 $un =~ s/[A-z\s=]//g;
577 $un = eval($un);
578 }
579}
580close(FDISK);
581print FLOG "get_un returns $un\n";
582return($un);
583}
584
585#
586# Parted gives info in MB
587# (depending on versions - 1.6.25.1 provides suffixes)
588#
589sub get_parted {
590
591my $device = shift;
592my $start = shift;
593my $end = shift;
594my $type = shift;
595my $void;
596my $d;
597my $n;
598my $ret;
599my $mode;
600my $size;
601my $unit;
602
603open (PARTED, "$parted -v |") || die "Unable to read from $parted";
604$d = <PARTED>;
605print FLOG "$d";
606close(PARTED);
607chomp($d);
608# parted version
609$d =~ s/[^0-9\.]*([0-9\.]+)$/$1/;
610my ($v,$maj,$min) = split(/\./,$d);
611# depending on parted version, information given change:
612if ($v == 2) {
613 # RHEL 6 parted 2.1
614 $mode=2;
615} elsif ($v == 1) {
616 if (($maj <= 5) || (($maj == 6) && (defined $min) && ($min < 25))) {
617 # RHEL 3 parted 1.6.3
618 # RHEL 4 parted 1.6.19
619 $mode=0;
620 } else {
621 # SLES 10 parted >= 1.6.25
622 $mode=1;
623 }
624} else {
625 $mode=-1;
626}
627print FLOG "mode: $mode\n";
628
629open (PARTED, "$parted -s $device print |") || die "Unable to read from $parted";
630# Skip 3 first lines
631$d = <PARTED>;
632$d = <PARTED>;
633$d = <PARTED>;
634
635if ($mode == 2) {
636 $d = <PARTED>;
637 $d = <PARTED>;
638 $d = <PARTED>;
639}
640print FLOG "Got from parted: \n";
641print FLOG "Minor Start End Filesystem\n";
642# Get info from each partition line
643while (($n,$d) = split(/\s/, <PARTED>,2)) {
644 chomp($d);
645 # v2 of parted ends with empty line
646 next if (($mode == 2) && ($n eq "") && ($d eq ""));
647 # v2 of parted starts with space potentially
648 ($n,$d) = split(/\s/, $d,2) if (($mode == 2) && ($n eq ""));
649 next if ($n !~ /^[1-9]/);
650 $d =~ s/^\s*//;
651 $d =~ s/\s+/ /g;
652 if ($mode == 0) {
653 ($$start{$n},$$end{$n},$$type{$n},$void) = split(/ /,$d);
654 $unit = 1;
655 } elsif ($mode == 1) {
656 ($$start{$n},$$end{$n},$size,$$type{$n},$void) = split(/ /,$d);
657 $unit = $mega;
658 } elsif ($mode == 2) {
659 ($$start{$n},$$end{$n},$size,$$type{$n},$void) = split(/ /,$d);
660 $unit = $mega;
661 } else {
662 die "Undefined mode $mode";
663 }
664 $$start{$n} = "" if (not defined $$start{$n});
665 $$end{$n} = "" if (not defined $$end{$n});
666 $$type{$n} = "" if (not defined $$type{$n});
667 # Handles potential suffixes in latest parted version. Return MB
668 $ret = decode_Bsuf($$start{$n},$unit);
669 $$start{$n} = $ret;
670 $ret = decode_Bsuf($$end{$n},$unit);
671 $$end{$n} = $ret;
672 print FLOG "$n $$start{$n} $$end{$n} $$type{$n}\n";
673}
674close(PARTED);
675}
676
677sub decode_Bsuf {
678
679my $size = shift;
680my $unit = shift;
681my $ret = 0;
682
683#print FLOG "decode_Bsuf input: $size / $unit ";
684if ($size =~ /K[B]*$/i) {
685 $size =~ s/K[B]*$//i;
686 $size *= 1024;
687} elsif ($size =~ /M[B]*$/i) {
688 $size =~ s/M[B]*$//i;
689 $size *= 1048576;
690} elsif ($size =~ /G[B]*$/i) {
691 $size =~ s/G[B]*$//i;
692 $size *= 1073741824;
693} elsif ($size =~ /T[B]*$/i) {
694 $size =~ s/T[B]*$//i;
695 $size *= 1099511627776;
696} else {
697 # Nothing to do
698}
699$ret = $size / $unit;
700#print FLOG " - output : $size => $ret\n";
701return($ret);
702}
703
704sub myexit {
705
706my $val=shift;
707
708close(FLOG);
709exit($val);
710}
711
712sub which_type {
713
714my $device = shift;
715my $type = "";
716
717open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
718while (<FDISK>) {
719 if ($_ =~ /EFI GPT/) {
720 $type= "gpt";
721 print FLOG "Found a GPT partition format\n";
722 last;
723 }
724}
725close(FDISK);
726open (PARTED, "$parted -s $device print|") || die "Unable to read from $fdisk";
727while (<PARTED>) {
728 if ($_ =~ /Disk label type: msdos/) {
729 $type= "msdos";
730 print FLOG "Found a msdos partition format\n";
731 last;
732 }
733}
734close(FDISK);
735return ($type);
736}
737
738sub mysyn {
739 print "Syntax: $0 [-l] device | [-s] partition\n";
740 myexit(-1);
741}
Note: See TracBrowser for help on using the repository browser.