source: MondoRescue/branches/3.0/mindi/parted2fdisk.pl@ 3336

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