package Disklabel; =head1 NAME Disklabel - manipulate Tru64 UNIX disklabels =head1 SYNOPSIS use Disklabel; $dl = Disklabel->new('disk-name'); # get values $val = $dl->prolog('sectors/unit'); $val = $dl->size('a'); $sectors = $dl->prolog('sectors/unit'); # set values $dl->size(a => 1024 * 1024); $dl->fstype(h => 'cnx'); $dl->offset(d => 1024 * 1024); $dl->prolog(label => 'clu_member1'); # write to disk $dl->write; # with exception handling... eval { $dl = Disklabel->new('disk-name'); }; if ($@) { print "oops\n"; } # ... and the write ... eval { $dl->write; }; if ($@) { print "oops\n"; } =head1 DESCRIPTION Disklabel provides a simple object-oriented interface to Tru64 UNIX disklabels. It is probably adaptable to other Unices, but I couldn't say. The "new" and "write" methods can cause an exception to be thrown, ("die"), so you may want to call them in an "eval {}" block. The disk-name should be specified without path information and without partition letter, i.e., C. Allowable partition-letters are C<[a-h]>. Disklabel.pm has only been tested on Tru64 UNIX V5.1. It may work on V4. The following methods are provided: =over 4 =item new(Edisk) returns an disklabel object with the disklabel information for the specified disk, or undef if the disk was not labelled. Can also return exceptions if something unexpected happens. =item size(Epartition-letterE [, Enew-sizeE]) retrieves or sets size associated with the partition-letter, depending on whether new-size is provided. =item offset(Epartition-letterE [, Enew-sizeE]) retrieves or sets offset (see C); =item fstype(Epartition-letterE [, Enew-sizeE]) retrieves or sets fstype (see C); =item prolog(EkeyE [, Enew-valueE]) retrieves or sets a prolog value, i.e. the "key: value" pairs that appear before the partition information. =item write(EdiskE) writes new partition-table to disk specified. =back =head1 VERSION This is version 0.1 (run away screaming). =head1 AUTHOR Robert Urban =cut BEGIN { $PERFORM_CLEANUP = 0; $DEBUG = 1; $VERBOSE = 1; $DISKLABEL = '/usr/sbin/disklabel'; } use FileHandle; #================================================================= # beginning of public interface #================================================================= sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; bless($self, $class); if (@_) { $self->{disk} = shift; my $ret = $self->_read(); defined($ret) || return undef; } else { die "must supply a disk-name"; } $self; } sub fstype { my $self = shift; my $part = shift; @_ ? $self->{ref}->{part}->{$part}->{fstype} = shift : $self->{ref}->{part}->{$part}->{fstype}; } sub offset { my $self = shift; my $part = shift; @_ ? $self->{ref}->{part}->{$part}->{offset} = shift : $self->{ref}->{part}->{$part}->{offset}; } sub size { my $self = shift; my $part = shift; @_ ? $self->{ref}->{part}->{$part}->{size} = shift : $self->{ref}->{part}->{$part}->{size}; } sub prolog { my $self = shift; my $field = shift; @_ ? $self->{ref}->{prolog}->{$field} = shift : $self->{ref}->{prolog}->{$field}; } sub write { my $self = shift; my $devname = shift; if (!$devname) { die "devname not specified"; } #my($devname, $dl_ref) = @_; $devname =~ s/[a-h]$//; #---------------------------------------- # write disklabel to file to be used to restore label #---------------------------------------- my $tmpfile = "/tmp/label-$devname"; $self->_print($tmpfile); #---------------------------------------- # restore edited label #---------------------------------------- my $cmd ="$DISKLABEL -r -R -t advfs $devname $tmpfile"; $VERBOSE && print "restoring disk label from [$tmpfile]\n"; executeCommand($cmd) || die "restore-disklabel to [$devname] failed"; #---------------------------------------- # cleanup #---------------------------------------- $PERFORM_CLEANUP && myUnlink($tmpfile); } #================================================================= # beginning of private interface #================================================================= sub _read { #my $disk = shift; my $self = shift; my $disk = $self->{disk}; my $debug = 0; if ($debug) {print "getDisklabel: disk=[$disk]\n";} $disk =~ s/[a-h]$//; my ($part, $size, $offset, $fstype, $fsize, $bsize); my $prolog; my $ref; my $fh = FileHandle->new; open($fh, "$DISKLABEL -r $disk 2>&1|") || die "popen disklabel"; my $in_prolog = 1; my $line = 0; while(<$fh>) { chomp; if ($debug) {print "LABEL> $_\n";} if (/No such device or address/) { die "non-existent disk [$disk]"; } if (/permission denied/i) { die "permission denied"; } if (/^Disk is unlabeled/) { close($fh); return undef; } #if (/^\s*#/) {$prolog .= $_; next;} if (!$in_prolog) { if (/^\s*#/) { if ($debug) {print " -COM2-\n";} $ref->{com2} = $_; next; } if (m{^\s+ ([a-h]) # partition :\s+ (\d+) # size \s+ (\d+) # offset \s+ (\S+) # fstype \s+ ( (\d+) # fsize \s+ (\d+) # bsize \s+ )? \#\s+}x) # the rest { if ($debug) {print " -matched p-line-\n";} ($part, $size, $offset, $fstype, $fsize, $bsize) = ($1, $2, $3, $4, $6, $7); #print " $part: $size $offset $fstype\n"; $ref->{part}->{$part} = { size => $size, offset => $offset, fstype => $fstype, fsize => $fsize, bsize => $bsize, }; } } else { $prolog .= "$_\n"; if (/^(\d+)\s+partitions:/) { if ($debug) {print " -setting in_prolog=0-\n";} $ref->{num_parts} = $1; $in_prolog = 0; next; } if (m!#\s+/dev\S+:$!) { if ($debug) {print " -COM1-\n";} $ref->{com1} = $_; } elsif (m!^([^:]+):(\s+(\S.*))?\s*$!) { #$key = $1; #$val = $3; $ref->{prolog}->{$1} = $3; if ($debug) {print " -prolog item: $1 = [$3]\n";} push(@{$ref->{prolog_order}}, $1); } } $line++; } close($fh); ($line < 5) && return undef; $ref->{old_prolog} = $prolog; $self->{ref} = $ref; } sub _print { my ($self, $file) = @_; my $dl_ref = $self->{ref}; my $fh = FileHandle->new; if ($file) { open($fh, ">$file") || die "can't write to $file"; } else { open($fh, ">&STDOUT") || die "can't dup stdout"; } print $fh $dl_ref->{com1}, "\n"; foreach my $key (@{$dl_ref->{prolog_order}}) { print $fh $key.': '.$dl_ref->{prolog}->{$key}."\n"; } print $fh "\n"; print $fh $dl_ref->{num_parts}, " partitions:\n"; print $fh $dl_ref->{com2}, "\n"; foreach my $part ('a' .. 'h') { if (!exists($dl_ref->{part}->{$part})) { next; } printf$fh "%3s: %10d %10d %9s %8d %5d\n", $part, $dl_ref->{part}->{$part}->{size}, $dl_ref->{part}->{$part}->{offset}, $dl_ref->{part}->{$part}->{fstype}, $dl_ref->{part}->{$part}->{fsize}, $dl_ref->{part}->{$part}->{bsize}; } close($fh); } sub executeCommand { my $cmd = shift; $VERBOSE && print " CMD: $cmd\n"; $DEBUG && return 1; # success return !system("$cmd 2>&1 > /dev/null"); } sub dump { my $self = shift; my $dl_ref = $self->{ref}; print "-------- PROLOG --------\n"; foreach my $key (@{$dl_ref->{prolog_order}}) { print $key.': '.$dl_ref->{prolog}->{$key}."\n"; } #$dl_ref->{prolog}, print "------------------------\n"; printf(" [%s]: %8s %8s %-8s\n", 'P', 'size', 'offset', 'fstype'); foreach my $part ('a' .. 'h') { printf(" [%s]: %8d %8d %-8s\n", $part, $dl_ref->{part}->{$part}->{size}, $dl_ref->{part}->{$part}->{offset}, $dl_ref->{part}->{$part}->{fstype}); } } 1;