#! /local/bin/perl5 -w # sjekkpart perl module use partition; package sjekkpart; sub init { return 1 if defined $init_done; $hosttype = `uname -sr`; chop $hosttype; # SunOS is the default: %func = ("dumpdates" => "read_dumpdates", "fstab" => "read_fstab", "discinfo" => "read_format"); if ($hosttype =~ /^SunOS 5/) { $func{'fstab'} = "read_vfstab"; } elsif ($hosttype =~ /^ULTRIX/) { $func{'discinfo'} = "read_chpt"; $func{'fstab'} = "read_dec_fstab"; } elsif ($hosttype =~ /^IRIX/) { $func{'discinfo'} = "read_dvhtool"; } %month_no = ("Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12); $init_done = 1; } sub run { local ($f) = shift; &init; die "Unknown function '$f'\n" unless defined $func{$f}; # print STDERR "Running '$f' -> \&$func{$f}\n"; eval "&".$func{$f}.";"; } sub partname { local ($disc, $slice) = @_; &init; if ($hosttype =~ /^(SunOS 5|IRIX)/) { # Device names like c0t0d0s0 return $disc."s".$slice; } else { # Device names like sd0a return $disc.$slice; } } ## ## Generic routines ## sub diskfree { my ($mount, $part) = @_; if ($mount =~ m,^/,) { if (open(STR, "df -k $mount |")) { while () { return $1 if /(\d+%)\s+$mount$/; } close (STR); } else { warn "df: $!\n"; } } elsif ($mount eq "Veritas") { my $disk = $vx_data{$part}->{"disk"}; my $free = $vx_data{$disk}->{"free"} / $vx_data{$disk}->{"size"}; return sprintf ("%d%%", 100 - 100 * $free); } return ""; } sub read_dumpdates { my ($part, $level, $date); my (%levels); my @parts; open (DUMPDATES, "/etc/dumpdates") || return; while () { chop; if (m,^/dev/(md/|vx/)?r(\S+)\s+\d+\s+\w+ (\w+) +(\d+) (\d+:\d+:\d+) (\d+),) { $date = sprintf ("$6-%02d-%02d-$5", $month_no{$3}, $4); $part = $2; if ($1) { my $type = $1; $part =~ s,dsk/,,; if ($type eq "md/") { @parts = &read_mddata ($part); } else { @parts = &read_vxdata ($part); } } else { @parts = ($part); } for (@parts) { s,.*/,,; next if defined $date{$_} && $date{$_} gt $date; $date{$_} = $date; $::dumpdate_bypart{$_} = $date; } } else { print STDERR "Ponder: '$_'\n"; } } close (DUMPDATES); } sub read_fstab { local ($part, $path, $fstype); open (FSTAB, "/etc/fstab") || die "Can't open /etc/fstab: $!\n"; while () { chop; s/\s*#.*//; s/^\s+//; next if /^$/; ($part, $path, $fstype) = (split (/\s+/))[0,1,2]; next unless $part =~ m,/dev/,; $part =~ s,.*/,,; $path = "swap" if $fstype eq "swap"; $::path_bypart{$part} = $path; # SunOS fører ikkje opp swap-partisjonen på rot-disken i fstab. if ($path eq "/") { $part =~ s/a$/b/; $::path_bypart{$part} = "swap"; } } close (FSTAB); } ## ## Special versions of the functions above ## ## Solaris sub read_vfstab { my ($part, $path, $fstype); my @parts; open (FSTAB, "/etc/vfstab") || die "Can't open /etc/vfstab: $!\n"; while () { chop; s/^\s+//; next if /^(#|$)/; ($part, $path, $fstype) = (split (/\s+/))[0,2,3]; next unless $part =~ m,/dev/,; if ($part =~ m,^/dev/md/dsk/,) { @parts = &read_mddata ($'); } elsif ($part =~ m,^/dev/vx/dsk/,) { @parts = &read_vxdata ($'); $path = "Veritas"; } else { @parts = $part; } for (@parts) { s,.*/,,; $path = "swap" if $fstype eq "swap"; $::path_bypart{$_} = $path; } } close (FSTAB); } sub read_mddata { my ($md) = @_; my @result = (); unless (%md_data) { if (open (METADB, "/usr/opt/SUNWmd/sbin/metadb|")) { while () { if (m,/dev/dsk/(\S+),) { $::path_bypart{$1} = "metadb"; } } close (METADB); } if (open (METASTAT, "/usr/opt/SUNWmd/sbin/metastat|")) { while () { if (m,^\w+: Submirror of (\w+), || m,^(\w+): Concat/Stripe,) { my $master = $1; while () { last if /^$/; if (/^\s+(c\d+t\d+d\d+s\d+)\s+/) { # print STDERR "Adding $1 to $master\n"; push (@{$md_data{$master}}, $1); } } } } close (METASTAT); } else { warn "/usr/opt/SUNWmd/sbin/metastat: $!\n"; %md_data = ("please report" => "only once"); } } warn "Couldn't find $md in md configuration\n" unless $md_data{$md}; return @{$md_data{$md}}; } sub read_vxdata { my ($dev) = @_; unless (%vx_data) { my $vol = ""; my $dg = ""; if (open (VXPRINT, "/usr/sbin/vxprint -A|")) { while () { $dg = $1 if /^dg\s+(\S+)/; if (/^dm\s+(\S+)\s+(\S+)\s+\S+\s+(\d+)/) { $vx_data{$1} = { "dev" => $2, "size" => $3, "free" => $3 }; $vx_data{$2} = { "disk" => $1 }; } $vol = "$dg/$1" if /^v\s+(\S+)/; if (/^sd\s+(\S+)-\d+\s+\S+\s+\S+\s+(\d+)/) { $vx_data{$1}->{"free"} -= $2; push (@{$vx_data{$vol}->{"devlist"}}, $vx_data{$1}->{"dev"}); } } close (VXPRINT); } else { warn "/usr/sbin/vxprint: $!\n"; %vx_data = ("foo" => "bar"); } } return @{$vx_data{$dev}->{"devlist"}} if $vx_data{$dev}; warn "Couldn't find $dev in Veritas configuration\n"; return (); } sub read_format { my ($num, @disc_bynum); $format = "/usr/sbin/format" if $hosttype =~ /^SunOS 5/; $format = "/usr/etc/format" if $hosttype =~ /^SunOS 4/; %disc_type = ("sbus SUNW,fas" => "F&W SCSI", "sbus ptisp" => "F&W diff SCSI", "sbus ptscII" => "diff SCSI", "pci scsi" => "F&W SCSI", "sbus esp" => "SCSI", "pci ide" => "IDE", ); $num = -1; open (FORMAT, "$format ) { if (/\d+\. (c\dt\d+d\d) <(.*?)\s*cyl (\d+) alt \d+ hd (\d+) sec (\d+)>/ || /(sd\d+): <(.*)cyl (\d+) alt \d+ hd (\d+) sec (\d+)>/) { ++$num; $::cyls_bydisc{$1} = $3; $::cylsize_bydisc{$1} = $4 * $5 / 2 / 1024; $disc_bynum[$num] = $1; $::description{$1} = $2; } elsif (m,(sbus|pci)@.*/([^@]+)@[^@]*@[^@]*$,) { my $dev = $disc_bynum[$num]; if (defined $disc_type{"$1 $2"}) { $::description{$dev} .= ", " . $disc_type{"$1 $2"}; } else { $::description{$dev} .= ", $1\@$2"; } } } close (FORMAT); local ($i, $file); $file = "/tmp/sc.$$"; open (SCRIPT, ">$file") || die "Can't write to $file: $!\n"; print SCRIPT "0\np\np\n"; for ($i = 1; $i <= $num; $i++) { print SCRIPT "q\ndisk\n$i\np\np\n"; } close (SCRIPT); local ($disc); $num = -1; open (FORMAT, "$format < $file 2> /dev/null |") || die "Can't run format: $!\n"; while () { if (/Current partition table/) { $disc = $disc_bynum[++$num]; $::part_bydisc{$disc} = new partition (0, $::cyls_bydisc{$disc}); } elsif (/^ (\d)\s+\w+\s+\w+\s+(\d+) -\s+(\d+)/) { # Solaris next unless defined $::path_bypart{&partname($disc, $1)}; $::part_bydisc{$disc}->add ($1, $2, $3 - $2 + 1); } elsif (/^\s+partition (\w) - starting cyl\s+(\d+).*\((\d+)/) { # SunOS next unless defined $::path_bypart{&partname($disc, $1)}; $::part_bydisc{$disc}->add ($1, $2, $3); } } close (FORMAT); unlink ($file); } ## Ultrix sub read_dec_fstab { local ($part, $path, $fstype); open (FSTAB, "/etc/fstab") || die "Can't open /etc/fstab: $!\n"; while () { chop; s/\s*#.*//; s/^\s+//; next if /^$/; ($part, $path, $fstype) = (split (/:/))[0,1,5]; next unless $part =~ m,/dev/,; $part =~ s,.*/,,; $path = "swap" if $fstype eq "sw"; $::path_bypart{$part} = $path; # Ultrix fører ikkje opp swap-partisjonen på rot-disken i fstab. if ($path eq "/") { $part =~ s/a$/b/; $::path_bypart{$part} = "swap"; } } close (FSTAB); } sub read_chpt { local ($disc, $part, @stack); DISC: for $disc () { open (CHPT, "/etc/chpt -q $disc 2>/dev/null|") || die "Can't run /etc/chpt: $!\n"; # Remove the "r" at the front and the "c" at the end: $disc =~ s,.*/r,,; $disc =~ s,c$,,; # We must store the output until we know the size of the disc # (partition c). @stack = (); while () { if (/^\s+([a-h])\s+(\d+)\s+(\d+)\s+(\d+)/) { if ($1 eq "c") { if ($2 != 0) { print STDERR "$d: Weird definition of c-partition!\n"; next DISC; } else { $::cylsize_bydisc{$disc} = 1/2048; $::cyls_bydisc{$disc} = $4; $::part_bydisc{$disc} = new partition (0, $4); } } push (@stack, $2, $3); } } undef $part; while ($#stack >= 0) { if (defined $part) { ++$part; } else { $part = 'a'; } $start = shift (@stack); $end = shift (@stack); next unless defined $::path_bypart{&partname($disc, $part)}; $::part_bydisc{$disc}->add ($part, $start, $end - $start + 1); } } close (CHPT); } ## Irix sub read_dvhtool { my ($num, @disc_bynum, $rootdev, $swapdev); if (defined $::path_bypart{"root"}) { $rootdev = (stat ("/dev/root"))[6]; } else { $rootdev = -1; } $swapdev = (stat ("/dev/swap"))[6]; $file = "/tmp/sc.$$"; open (SCRIPT, ">$file") || die "Can't write to $file: $!\n"; print SCRIPT "p\nl\nq\nq\n"; close (SCRIPT); $num = -1; opendir (DEV, "/dev/rdsk") || die "/dev/rdsk:$!\n"; while (defined ($dev = readdir (DEV))) { if ((stat ("/dev/rdsk/$dev"))[6] == $rootdev) { $::path_bypart{$dev} = "/"; } if ((stat (_))[6] == $swapdev) { $::path_bypart{$dev} = "swap"; } } closedir (DEV); opendir (DEV, "/dev/rdsk") || die "/dev/rdsk:$!\n"; while (defined ($dev = readdir (DEV))) { next unless $dev =~ /vh$/; my $disc = $dev; $disc =~ s/vh$//; # We need to store the partition table somewhere since # the disc size is unknown, i.e. we can't create the partition # object before slice 10 is reached in the output from dvhtool. my @temp = (); my $i; open (R, "/sbin/dvhtool /dev/rdsk/$dev < $file 2>/dev/null|") || die "dvhtool:$!\n"; while () { if (/^\s+(\d+):\s+(\d+)\s+(\d+)\s+(\S+)/) { my ($slice, $n_blks, $first_blk, $type) = ($1, $2, $3, $4); if ($slice == 0) { $disc_bynum[++$num] = $disc; } elsif ($type eq "volume") { $::cylsize_bydisc{$disc} = 512 / 1024/1024; $::cyls_bydisc{$disc} = $n_blks; $::part_bydisc{$disc} = new partition (0, $n_blks); } $temp[$slice] = [ $n_blks, $first_blk, $type ]; } } # Now we can add the used partitions to the object. for $i (0..$#temp) { if (defined $temp[$i]) { if (defined $::path_bypart{$disc . "s" . $i}) { $::part_bydisc{$disc}->add ($i, $temp[$i][1], $temp[$i][0]); } elsif ($temp[$i][2] =~ /^(volhdr|xfslog)/) { $::part_bydisc{$disc}->add ($i, $temp[$i][1], $temp[$i][0]); $::path_bypart{$disc . "s" . $i} = $temp[$i][2]; } } } } closedir DEV; unlink ($file); } 1;