source: branches/3.0-mindi-2.1/mindi/parted2fdisk.pl @ 3563

Last change on this file since 3563 was 3563, checked in by Bruno Cornec, 4 years ago

Many additional backports from 3.2 and 3.0 future

  • Improved support for systemd
  • Launch start-netfs when a network conf is detected in the conf file to avoid an error later on in automatic mode
  • Property svn:keywords set to Id
File size: 16.8 KB
Line 
1#!/usr/bin/perl -w
2#
3# $Id: parted2fdisk.pl 3563 2016-04-11 17:43:30Z 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.