source: branches/stable/mindi/parted2fdisk.pl @ 1903

Last change on this file since 1903 was 1903, checked in by bruno, 11 years ago

merge -r 1842:1889 2.2.5

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