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

Last change on this file since 3344 was 3344, checked in by Bruno Cornec, 9 years ago
  • parted2fdisk now calls fdisk with the parameters when not using the embedded code. Ready to be the only call in mondo now
  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1#!/usr/bin/perl -w
2#
3# $Id: parted2fdisk.pl 3344 2015-02-13 19:39:50Z 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 with $args $device\n";
373
374if ($args =~ /^-/) {
375 # -l or -s
376 open (FDISK, "$fdisk $args $device 2>/dev/null |") || die "Unable to read from $fdisk";
377 while (<FDISK>) {
378 print $_;
379 }
380 close(FDISK);
381} else {
382 # Modification mode
383 open (FDISK, "| $fdisk $args $device 2>/dev/null") || die "Unable to modify through $fdisk";
384 while (<STDIN>) {
385 print FDISK $_;
386 }
387 close(FDISK);
388 close(STDIN);
389}
390myexit(0);
391
392
393# Is your system LSB ?
394sub is_lsb {
395
396my $cmd = shift;
397my $basename = basename($cmd);
398
399if (not (-x $cmd)) {
400 print FLOG "Your system is not LSB/mondo compliant: $basename was not found as $cmd\n";
401 print FLOG "Searching elswhere...";
402 foreach $i (split(':',$ENV{PATH})) {
403 if (-x "$i/$basename") {
404 $cmd = "$i/$basename";
405 print FLOG "Found $cmd, using it !\n";
406 last;
407 }
408 }
409 if (not (-x $cmd)) {
410 print FLOG "Your system doesn't provide $basename in the PATH\n";
411 print FLOG "Please correct it before relaunching\n";
412 myexit(-1);
413 }
414}
415return($cmd);
416}
417
418sub fdisk_list {
419
420my $device = shift;
421my $wpart = shift;
422my $start = shift;
423my $end = shift;
424my $verbose = shift;
425
426my $un;
427my $endmax;
428my $d;
429my $n;
430
431my %cmt = ( "FAT" => "FAT",
432 "ext2" => "Linux",
433 "ext3" => "Linux",
434 "ext4" => "Linux",
435 "xfs" => "Linux",
436 "reiserfs" => "Linux",
437 "linux-swap" => "Linux swap",
438 "lvm" => "Linux LVM",
439 "raid" => "RAID Linux auto",
440 "fat16" => "fat16",
441 "fat32" => "fat32",
442 "" => "Linux",
443);
444
445my $part;
446my $mstart;
447my $mend;
448my $length;
449my $pid;
450my $cmt;
451format FLOG1 =
452@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
453$part, $mstart, $mend, $length, $pid, $cmt
454.
455format FLOG2 =
456@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
457$part,
458 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
459 $mstart, $mend, $length, $pid, $cmt
460.
461format STDOUT1 =
462@<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
463$part, $mstart, $mend, $length, $pid, $cmt
464.
465format STDOUT2 =
466@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
467$part,
468 @>>>>>>>>>> @>>>>>>>>>> @>>>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<
469 $mstart, $mend, $length, $pid, $cmt
470.
471# Device Boot Start End Blocks Id System
472#/dev/hda1 1 77579 39099374+ ee EFI GPT
473
474
475#
476# Keep Fdisk headers
477#
478# this will return bytes
479$un = get_un ($device,$wpart,$verbose);
480
481$endmax = get_max($device);
482
483# This will return MB
484get_parted ($device,$start,$end,\%type);
485
486while (($n,$d) = each %type) {
487 # Print infos fdisk like
488 $part = ${device}.$n;
489 # start and end are in cylinder in fdisk format
490 # so return in MB * 1MB / what represents 1 cyl in B
491 $mstart = sprintf("%d",$$start{$n}*$mega/$un);
492 $mstart = 1 if ($mstart < 1);
493 $mstart = $endmax if ($mstart > $endmax);
494 $mend = sprintf("%d",$$end{$n}*$mega/$un - 1);
495 $mend = $endmax if ($mend > $endmax);
496 $mend = 1 if ($mend < 1);
497 # length is in 1K blocks
498 $length = sprintf("%d",($mend-$mstart+1)*$un/1024);
499 $pid = $pid{$type{$n}};
500 $cmt = $cmt{$type{$n}};
501 #print FLOG "$part - $mstart - $mend - $length\n";
502
503 if ($verbose == 1) {
504 if (not (defined $wpart)) {
505 if (length($part) > 13) {
506 open(STDOUT2,">&STDOUT") || die "Unable to open STDOUT2";
507 select(STDOUT2);
508 write;
509 open(FLOG2,">&FLOG") || die "Unable to open FLOG2";
510 select(FLOG2);
511 write;
512 select(STDOUT);
513 close(FLOG2);
514 close(STDOUT2);
515 } else {
516 open(STDOUT1,">&STDOUT") || die "Unable to open STDOUT1";
517 select(STDOUT1);
518 write;
519 open(FLOG1,">&FLOG") || die "Unable to open FLOG1";
520 select(FLOG1);
521 write;
522 select(STDOUT);
523 close(FLOG1);
524 close(STDOUT1);
525 }
526 } else {
527 # manage the -s option of fdisk here
528 print "$length\n" if ($part eq $wpart);
529 print FLOG "$part has $length KBytes\n" if ($part eq $wpart);
530 }
531 }
532}
533close(FDISK);
534close(PARTED);
535}
536
537#
538# Get max size from fdisk
539#
540sub get_max {
541
542my $device = shift;
543my $max = 0;
544my $foo;
545
546open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
547while (<FDISK>) {
548 if ($_ =~ /heads/) {
549 chomp;
550 $max = $_;
551 $max =~ s/.* ([0-9]+) cylinders/$1/;
552 }
553}
554close(FDISK);
555print FLOG "get_max returns $max\n";
556return($max);
557}
558
559#
560# Get units from fdisk (cylinder size)
561#
562sub get_un {
563
564my $device = shift;
565my $wpart = shift;
566my $verbose = shift;
567my $un = 0;
568my $foo;
569
570open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
571while (<FDISK>) {
572 print if (($_ !~ /^\/dev\//) and (not (defined $wpart)) and ($verbose == 1));
573 if ($_ =~ /^Units/) {
574 ($foo, $un , $foo) = split /=/;
575 $un =~ s/[A-z\s=]//g;
576 $un = eval($un);
577 }
578}
579close(FDISK);
580print FLOG "get_un returns $un\n";
581return($un);
582}
583
584#
585# Parted gives info in MB
586# (depending on versions - 1.6.25.1 provides suffixes)
587#
588sub get_parted {
589
590my $device = shift;
591my $start = shift;
592my $end = shift;
593my $type = shift;
594my $void;
595my $d;
596my $n;
597my $ret;
598my $mode;
599my $size;
600my $unit;
601
602open (PARTED, "$parted -v |") || die "Unable to read from $parted";
603$d = <PARTED>;
604print FLOG "$d";
605close(PARTED);
606chomp($d);
607# parted version
608$d =~ s/[^0-9\.]*([0-9\.]+)$/$1/;
609my ($v,$maj,$min) = split(/\./,$d);
610# depending on parted version, information given change:
611if ($v == 2) {
612 # RHEL 6 parted 2.1
613 $mode=2;
614} elsif ($v == 1) {
615 if (($maj <= 5) || (($maj == 6) && (defined $min) && ($min < 25))) {
616 # RHEL 3 parted 1.6.3
617 # RHEL 4 parted 1.6.19
618 $mode=0;
619 } else {
620 # SLES 10 parted >= 1.6.25
621 $mode=1;
622 }
623} else {
624 $mode=-1;
625}
626print FLOG "mode: $mode\n";
627
628open (PARTED, "$parted -s $device print |") || die "Unable to read from $parted";
629# Skip 3 first lines
630$d = <PARTED>;
631$d = <PARTED>;
632$d = <PARTED>;
633
634if ($mode == 2) {
635 $d = <PARTED>;
636 $d = <PARTED>;
637 $d = <PARTED>;
638}
639print FLOG "Got from parted: \n";
640print FLOG "Minor Start End Filesystem\n";
641# Get info from each partition line
642while (($n,$d) = split(/\s/, <PARTED>,2)) {
643 chomp($d);
644 # v2 of parted ends with empty line
645 next if (($mode == 2) && ($n eq "") && ($d eq ""));
646 # v2 of parted starts with space potentially
647 ($n,$d) = split(/\s/, $d,2) if (($mode == 2) && ($n eq ""));
648 next if ($n !~ /^[1-9]/);
649 $d =~ s/^\s*//;
650 $d =~ s/\s+/ /g;
651 if ($mode == 0) {
652 ($$start{$n},$$end{$n},$$type{$n},$void) = split(/ /,$d);
653 $unit = 1;
654 } elsif ($mode == 1) {
655 ($$start{$n},$$end{$n},$size,$$type{$n},$void) = split(/ /,$d);
656 $unit = $mega;
657 } elsif ($mode == 2) {
658 ($$start{$n},$$end{$n},$size,$$type{$n},$void) = split(/ /,$d);
659 $unit = $mega;
660 } else {
661 die "Undefined mode $mode";
662 }
663 $$start{$n} = "" if (not defined $$start{$n});
664 $$end{$n} = "" if (not defined $$end{$n});
665 $$type{$n} = "" if (not defined $$type{$n});
666 # Handles potential suffixes in latest parted version. Return MB
667 $ret = decode_Bsuf($$start{$n},$unit);
668 $$start{$n} = $ret;
669 $ret = decode_Bsuf($$end{$n},$unit);
670 $$end{$n} = $ret;
671 print FLOG "$n $$start{$n} $$end{$n} $$type{$n}\n";
672}
673close(PARTED);
674}
675
676sub decode_Bsuf {
677
678my $size = shift;
679my $unit = shift;
680my $ret = 0;
681
682#print FLOG "decode_Bsuf input: $size / $unit ";
683if ($size =~ /K[B]*$/i) {
684 $size =~ s/K[B]*$//i;
685 $size *= 1024;
686} elsif ($size =~ /M[B]*$/i) {
687 $size =~ s/M[B]*$//i;
688 $size *= 1048576;
689} elsif ($size =~ /G[B]*$/i) {
690 $size =~ s/G[B]*$//i;
691 $size *= 1073741824;
692} elsif ($size =~ /T[B]*$/i) {
693 $size =~ s/T[B]*$//i;
694 $size *= 1099511627776;
695} else {
696 # Nothing to do
697}
698$ret = $size / $unit;
699#print FLOG " - output : $size => $ret\n";
700return($ret);
701}
702
703sub myexit {
704
705my $val=shift;
706
707close(FLOG);
708exit($val);
709}
710
711sub which_type {
712
713my $device = shift;
714my $type = "";
715
716open (FDISK, "$fdisk -l $device 2>/dev/null |") || die "Unable to read from $fdisk";
717while (<FDISK>) {
718 if ($_ =~ /EFI GPT/) {
719 $type= "gpt";
720 print FLOG "Found a GPT partition format\n";
721 last;
722 }
723}
724close(FDISK);
725open (PARTED, "$parted -s $device print|") || die "Unable to read from $fdisk";
726while (<PARTED>) {
727 if ($_ =~ /Disk label type: msdos/) {
728 $type= "msdos";
729 print FLOG "Found a msdos partition format\n";
730 last;
731 }
732}
733close(FDISK);
734return ($type);
735}
736
737sub mysyn {
738 print "Syntax: $0 [-l] device | [-s] partition\n";
739 myexit(-1);
740}
Note: See TracBrowser for help on using the repository browser.