#!/usr/bin/perl -w
#
# findbill - Search a drive for UFS backup superblocks. Prints potential
#            backups for use with "fsck -o b=...". Perl, Solaris.
#
# This works by looking for the UFS magic number at specific locations, and
# does have a small potential for false positives. The magic number is
# 0x011954, which I've heard is either Bill Joy's or Marshall Kirk McKusick's
# birthday (hence the name).
# 
# This now also searches for MTB_UFS magic numbers (0xdecade).
#
# 23-Jan-2006, ver 1.55 
#
# USAGE:    findbill raw-special-device
#    eg, 
#           findbill /dev/rdsk/c0t0d0s0
#
# Note: realistically you wouldn't want to try anything past your third
# backup super block - by that point it's time to restore from tape.
#
# COPYRIGHT: Copyright (c) 2006 Brendan Gregg.
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#  (http://www.gnu.org/copyleft/gpl.html)
#
# 21-Mar-2004   Brendan Gregg   Created this.
# 17-Jan-2005      "      "     Added MTB_UFS.
# 10-Jan-2006      "      "     Added last write time and mountpoint fields.
# 23-Jan-2006      "      "     Tweaked style.

use strict;

### Check Argument

my $pathname = defined $ARGV[0] ? $ARGV[0] : "";
die "USAGE: findbill raw-special-device\n" if $pathname =~ /^(-h|--help|)$/;
unless (-c "$pathname" || -b "$pathname") {
    print STDERR "WARNING: $pathname isn't a raw-special-device.\n\n";
    # this is probably a typo, but it may be ok - eg, when running
    # findbill on a dd image of UFS.
}

### Variables

my $MAGIC1 = 0x011954;
my $MAGIC2 = 0xdecade;
my $block = 0;
my $offset = 0;
my ($time, $name, $int, $junk);

### Search for magic number

open RAW, "$pathname" or die "ERROR1: Can't open $pathname: $!\n";
print "Searching $pathname,\n\n";
printf "%-8s %-8s %-25s %s\n",
       "Type", "Block", "Time last written", "Mountpoint";

while ( read(RAW, my $buffer, 512) > 0) {
    if ($block == 0) {
        ($junk, $time, $junk, $name) = unpack('a32La176Z302', $buffer);
    }
    elsif ($block == 2) {
        ($junk, $int) = unpack('a348L', $buffer);
        if ($int == $MAGIC1) {
            printf("%-8s %-8d %-25s %s\n", "UFS", $offset/512 - 2,
                   scalar localtime($time), $name);
        }
        elsif ($int == $MAGIC2) {
            printf("%-8s %-8d %-25s %s\n", "MTB_UFS", $offset/512 - 2,
                   scalar localtime($time), $name);
        }
    }
    $block = 0 if ++$block > 15;
    $offset += 512;
    $buffer = "";
}

close RAW;
