source: branches/2.2.9/mindi/parted2fdisk.pl @ 2154

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