From: Stefan Bund Date: Fri, 6 Nov 2009 12:51:04 +0000 (+0100) Subject: modularize X-Git-Url: http://g0dil.de/git?p=mapsector.git;a=commitdiff_plain;h=1f26a61aac4fa8d86ce7b32b7f22b977d8f1f7d1 modularize --- diff --git a/lib/00_utilities.sh b/lib/00_utilities.sh new file mode 100644 index 0000000..069fbc0 --- /dev/null +++ b/lib/00_utilities.sh @@ -0,0 +1,15 @@ +deviceid() +{ + ls -lL "$1" 2>/dev/null | awk -F '[ ,]+' '{print "(" $5 ", " $6 ")"}' +} + +dmcryptmap() +{ + devnums="`deviceid $1`" + + dmsetup ls --target crypt | awk '{print $1}' | while read dmdev; do + if dmsetup deps $dmdev | grep -qF "$devnums"; then + echo "/dev/mapper/$dmdev" + fi + done +} diff --git a/lib/10_map_raid.sh b/lib/10_map_raid.sh new file mode 100644 index 0000000..7c1b462 --- /dev/null +++ b/lib/10_map_raid.sh @@ -0,0 +1,33 @@ +detect_raid() +{ + which mdadm >/dev/null 2>&1 && mdadm -Q $device | grep -qF -- "--examine" +} + +describe_raid() +{ + echo " RAID level 1" +} + +map_raid() +{ + local mddevice + local mdlevel + + mddevice="`mdadm -Q $device | sed -ne 's/.*\(raid[0-9] \/dev\/[^.]*\).*/\1/' -eT -ep`" + + if [ -z "$mddevice" ]; then + echo "! raid master device for raid componentn device $device not found" 1>&2 + exit 1 + fi + + mdlevel="${mddevice% *}" + mddevice="${mddevice#* }" + + echo "device $mddevice md" + echo "raidlevel $mdlevel" + echo "sector $sector" + + device="$mddevice" +} + +register_mapper "raid" diff --git a/lib/10_scan_mountpoint.sh b/lib/10_scan_mountpoint.sh new file mode 100644 index 0000000..e020fb9 --- /dev/null +++ b/lib/10_scan_mountpoint.sh @@ -0,0 +1,29 @@ +detect_mountpoint() +{ + true +} + +describe_mountpoint() +{ + true +} + +do_mountpoint() +{ + local devnums + devnums="`deviceid $device`" + + while read dev dir opts; do + case "$dev" in + *:*) ;; + *) + if [ "$devnums" == "`deviceid $dev`" ]; then + echo "mountpoint $dir" + break + fi + ;; + esac + done < /proc/mounts +} + +register_scanner "mountpoint" diff --git a/lib/50_map_crtypt.sh b/lib/50_map_crtypt.sh new file mode 100644 index 0000000..4ec0ec0 --- /dev/null +++ b/lib/50_map_crtypt.sh @@ -0,0 +1,49 @@ +detect_crypt() +{ + which cryptsetup >/dev/null 2>&1 && [ -n "`dmcryptmap $device`" ] +} + +describe_crypt() +{ + echo " cryptsetup (luks and dmcrypt)" +} + +map_crypt() +{ + # Step 2: Find the crypted volume defined for this partition + + local offset + local devnums + local cryptdev + local cryptsector + local type + + offset="`cryptsetup luksDump $device 2>/dev/null | awk '/^Payload offset/{print $3}'`" + + if [ -z "$offset" ]; then + # Plain dmcrypt + offset=0 + type=dmcrypt + else + type=luks + fi + + cryptdev="`dmcryptmap $device`" + + if [ -z "$cryptdev" ]; then + echo "! Failed to find decrypted mapper device for $device" + exit 1; + fi + + cryptsector="`dc -e "$sector $offset - p"`" #`" + + echo "offset $offset" + echo "device $cryptdev crypt" + echo "type $type" + echo "sector $cryptsector" + + device="$cryptdev" + sector="$cryptsector" +} + +register_mapper "crypt" diff --git a/lib/50_map_lvm.sh b/lib/50_map_lvm.sh new file mode 100644 index 0000000..51fbffc --- /dev/null +++ b/lib/50_map_lvm.sh @@ -0,0 +1,86 @@ +detect_lvm() +{ + which pvdisplay >/dev/null 2>&1 && pvdisplay $device >/dev/null 2>&1 +} + +describe_lvm() +{ + echo " LVM (linear allocation scheme)" +} + +map_lvm() +{ + local pvname + local pesize + local vgname + local pestart + local penum + local subsector + local lestart + local firstpe + local lenum + local fsdev + local fssector + + # Step 3: Get pysical extent number + + pvname="`pvdisplay -c $device 2>/dev/null | awk -F: '{print $1,$2,$8}' | sed -e 's/^ *//'`" + + if [ -z "$pvname" ]; then + echo "! $device is not a physical volume" 1>&2 + exit 1 + fi + + pesize="${pvname##* }" + vgname="${pvname% *}" + pvname="${vgname% *}" + vgname="${vgname#* }" + pesize="`dc -e "$pesize 2 * p"`" #`" + pestart="`pvs --unit s -ope_start $device 2>/dev/null | sed -n -e 's/ *//g' -e 's/S.*$//' -e '$p'`" + penum="`dc -e "$sector $pestart - $pesize ~ n [ ] n p"`" #`" + subsector="${penum% *}" + penum="${penum#* }" + + echo "device $pvname pv" + echo "offset $pestart" + echo "pesize $pesize" + echo "extent $penum" + echo "subsector $subsector" + echo "group $vgname" + + # Step 4: Find associated logical volume + + lestart="$(vgdisplay -v $vgname 2>/dev/null | awk '/LV Name/{print $3}' | while read lvname; do \ + lvdisplay -m $lvname 2>/dev/null \ + | awk -v RS="\n *\n( --- Segments ---\n)?" \ + -F"[ \t\n:]+" \ + -v pvname="$pvname" \ + -v penum="$penum" \ + -v lvname="$lvname" \ + '$0 ~ "Physical volume[ \t]+" pvname && $14<=penum && $16>=penum{print lvname,$4,$14}'; \ + done)" + + if [ -z "$lestart" ]; then + echo "# pysical extent $penum of $pvname is not mapped in any logical volume" 1>&2 + exit 0 + fi + + lvname="${lestart%% *}" + lestart="${lestart#* }" + firstpe="${lestart#* }" + lestart="${lestart% *}" + lenum="`dc -e "$penum $firstpe - $lestart + p"`" #`" + + echo "device $lvname lv" + echo "extent $lenum" + + fsdev="$lvname" + fssector="`dc -e "$lenum $pesize * $subsector + p"`" #`" + + echo "sector $fssector" + + device="$fsdev" + sector="$fssector" +} + +register_mapper "lvm" diff --git a/lib/50_map_partition.sh b/lib/50_map_partition.sh new file mode 100644 index 0000000..1e16873 --- /dev/null +++ b/lib/50_map_partition.sh @@ -0,0 +1,38 @@ +detect_partition() +{ + [ -z "`fdisk -l $device 2>&1 >/dev/null`" ] +} + +describe_partition() +{ + echo " partition tables" +} + +map_partition() +{ + # Step 1: Find partition to which this sector belongs + + local partdev + local partstart + local partsector + + partdev="`fdisk -ul $device | awk -v sector="$sector" -F '[ *]+' '/^\// && !/Extended$/ && $2<=sector && $3>=sector {print $1,$2}'`" #`" + + if [ -z "$partdev" ]; then + echo "# sector $sector is not part of any partition on $device" 1>&2 + exit 0 + fi + + partstart="${partdev#* }" + partdev="${partdev% *}" + partsector="`dc -e "$sector $partstart - p"`" # `" + + echo "offset $partstart" + echo "device $partdev partition" + echo "sector $partsector" + + device="$partdev" + sector="$partsector" +} + +register_mapper "partition" diff --git a/lib/50_scan_extfs.sh b/lib/50_scan_extfs.sh new file mode 100644 index 0000000..cccf7f7 --- /dev/null +++ b/lib/50_scan_extfs.sh @@ -0,0 +1,80 @@ +detect_extfs() +{ + which tune2fs >/dev/null 2>&1 && tune2fs -l $device >/dev/null 2>&1 +} + +describe_extfs() +{ + echo " ext2-4" +} + +scan_extfs() +{ + local fsblocksize + local fsblock + local fssubsector + local fstype + local inode + + fstype="`file -s $device | sed -e 's/.*\(ext[0-9]\).*/\1/'`" + echo "fstype $fstype" + + # Step 6: Get filesystem blocksize and convert sector number to filesystem block number + + fsblocksize="`tune2fs -l $device | awk '/Block size/{print $3/512}'`" + + if [ -z "$fsblocksize" ]; then + echo "! $device is not ext2/ext3" 1>&2 + exit 1 + fi + + fsblock="`dc -e "$sector $fsblocksize ~ n [ ] n p"`" #`" + fssubsector="${fsblock% *}" + fsblock="${fsblock#* }" + + echo "blocksize $fsblocksize" + echo "block $fsblock" + echo "subsector $fssubsector" + + # Step 7: Check, whether block is in use + + if echo "testb $fsblock" | debugfs $device 2>/dev/null | grep -qF "not in use"; then + echo "blockstate free" + exit 0 + fi + echo "blockstate used" + + # Step 8: Find inode, to which the block belongs + + inode="`echo "icheck $fsblock" | debugfs $device 2>/dev/null | awk 'FNR>1{print $2}'`" #`" + + if [ -z "$inode" ]; then + echo "blocktype meta?" + exit 0 + fi + + echo "inode $inode" + + # Step 9: Find file name(s) referencing the inode + + ( + namefound="$(\ + echo "ncheck $inode" \ + | debugfs $device 2>/dev/null \ + | sed -e '1d' -e 's/^[0-9]*[ ]*//' -e 's/^\/\//\//' \ + | while read name; do \ + if [ -z "$firstname" ]; then \ + echo "blocktype data" 1>&3; \ + echo "1"; \ + firstname=1; \ + fi; \ + echo "name $name" 1>&3; \ + done \ + )" + if [ -z "$namefound" ]; then + echo "blocktype journal?" + fi + ) 3>&1 +} + +register_scanner "extfs" diff --git a/lib/50_scan_reiserfs.sh b/lib/50_scan_reiserfs.sh new file mode 100644 index 0000000..6d44cf3 --- /dev/null +++ b/lib/50_scan_reiserfs.sh @@ -0,0 +1,174 @@ +detect_reiserfs() +{ + which debugreiserfs >/dev/null 2>&1 && debugreiserfs $device >/dev/null 2>&1 +} + +describe_reiserfs() +{ + echo " reiserfs" +} + +scan_reiserfs() +{ + local blocksize + local block + local subsector + + echo "fstype reiserfs" + + # Step 6: Get filesystem blocksize and convert sector number to filesystem block number + + blocksize="`debugreiserfs $device 2>/dev/null | awk '/^Blocksize:/{print $2/512}'`" + + if [ -z "$blocksize" ]; then + echo "! $device is not reiserfs" 1>&2 + exit 1 + fi + + block="`dc -e "$sector $blocksize ~ n [ ] n p"`" #`" + subsector="${block% *}" + block="${block#* }" + + echo "blocksize $blocksize" + echo "block $block" + echo "subsector $subsector" + + # Step 7: Check, whether block is in use + + if debugreiserfs -1 $block $device 2>&1 >/dev/null | grep -qF "free in ondisk bitmap"; then + echo "blockstate free" + exit 0 + fi + echo "blockstate used" + + # Use debugreiserfs -1 to check the block type. This however only works if the block is readable. + type="`debugreiserfs -1 $block $device 2>/dev/null | sed -e '/^=*$/d' | head -1`" + + case "$type" in + "Looks like unformatted") type="data" ;; + "Reiserfs super block"*) type="superblock" ;; + "LEAF NODE"*) type="meta" ;; + "INTERNAL NODE"*) type="meta" ;; + "Desc block"*) type="journal" ;; + *) type="" ;; + esac + + if [ -n "$type" ]; then + echo "blocktype $type" + fi + + # Step 8: Find object id to which this block belongs + # Step 9: Find file name(s) referencing this object id + + # Currently we only look for $block in indirect blocks. + + python - $device $block </dev/null" % device) + +def parse_leafnode(): + global fp + l = fp.readline() + #sys.stderr.write("> leafnode(1): %s\n" % repr(l)) + if not l.startswith("LEAF NODE") : return + for i in range(4) : fp.readline() + while True: + l = fp.readline() + #sys.stderr.write("> leafnode(2): %s\n" % repr(l)) + parts = l.split("|") + if len(parts)<2 : return + parts = parts[2].split() + if len(parts)<4 : return + obid=(int(parts[0]),int(parts[1])) + if parts[3] == "DIR" : parse_dir(obid) + elif parts[3] == "IND" : parse_indirect(obid) + else: + while True: + l = fp.readline().strip() + #sys.stderr.write("> leafnode(3): %s\n" % repr(l)) + if l == 79*"-" or l == 67*"=" : break + +def parse_dir(obid): + global fp + global dirtree + fp.readline() + while True: + try: + l = fp.readline().rstrip() + #sys.stderr.write("> dir: %s\n" % repr(l)) + if l == 79*"-" or l == 67*"=": return + if l.endswith("not set"): continue + i = l.index("\"(") + name = l[6:6+int(l[i+2:i+5])] + if name == "." or name == ".." : continue + i = l.index("[",len(name)+12) + entryid = tuple(map(int,l[i+1:l.index("]",i+1)].split())) + entry = dirtree.get(entryid) + if entry is None : entry = dirtree[entryid] = set() + entry.add((name,obid)) + except ValueError: + pass + +def parse_indirect(obid): + global fp + global blocknr + global blockid + fp.readline() + for pointer in fp.readline().strip()[1:-1].split(): + i = pointer.find("(") + if i == -1: + blkmin = blkmax = int(pointer) + else: + blkmin = int(pointer[:i]) + blkmax = blkmin+int(pointer[i+1:-1])-1 + if blocknr >= blkmin and blocknr <= blkmax: + blockid = obid + fp.readline() + +def scan_path(id): + global dirtree + entry = dirtree.get(id) + #sys.stderr.write("> scan_path: %s->%s\n" % (id, entry)) + if entry is None: + return [ '/' ] + else: + rv = [] + for name, parent in entry: + for path in scan_path(parent): + rv.append(os.path.join(path,name)) + return rv + +def parse(): + global fp + while True: + while True: + l = fp.readline() + #sys.stderr.write("> parse: %s\n" % repr(l)) + if not(l) : return + if l.strip() == 67*"=" : break + parse_leafnode() + +parse() + +if blockid is None: + sys.exit(0) + +sys.stdout.write("objectid %d %d\n" % blockid) + +for path in scan_path(blockid): + if path != '/': + sys.stdout.write("name %s\n" % path) +EOF + +} + +register_scanner "reiserfs" diff --git a/mapsector b/mapsector new file mode 100755 index 0000000..c3de5a8 --- /dev/null +++ b/mapsector @@ -0,0 +1,136 @@ +#!/bin/sh + +########################################################################### + +mappers="" +scanners="" + +register_mapper() +{ + mappers="${mappers}${mappers:+ }$1" +} + +register_scanner() +{ + scanners="${scanners}${scanners:+ }$1" +} + +load() +{ + for lib in `ls "$1"/[0-9][0-9]_*.sh | sort`; do + source $lib + done +} + +# Map device/sector through blockdevice mappings (e.g. lvm) + +run() +{ + local found + foundm=1 + while [ -n "$found" ]; do + found="" + for name in "$@"; do + if detect_$name; then + found=1 + if do_$name; then + return + fi + break + fi + done + done +} + +########################################################################### + +unset LANG + +#### Find library directory and load library files + +name="`basename "$0"`" +X="`dirname "$0"`" +if [ "`basename "$X"`" == "bin" ]; then # `" + libdir="`dirname "$X"`/lib/$name" #`" +fi +if [ -z "$libdir" -o ! -d "$libdir" ]; then + libdir="$X/lib" +fi + +if [ ! -d "$libdir" ]; then + echo "! Library directory not found" 1>&2 + exit 1 +fi + +load "$libdir" + +#### Parse command line arguments + +X=`getopt -o "h" --long "help,noscan" -n "$name" -- "$@"` +if [ $? != 0 ]; then exit 1; fi +eval set -- "$X" + +noscan="" +help="" + +while true; do + case "$1" in + -h|--help) help="0"; shift ;; + --noscan) noscan="0"; shift ;; + --) shift; break ;; + *) echo "! internal error"; exit 1 ;; + esac +done + +if [ -n "$help" -o -z "$2" ]; then + cat < " + +mapsector -- Map sector numbers to file name(s) + +Given a device and a sector number, mapsector will try to find the +file name(s) mapping to this sector. It will try to gather as much +information about the given sector as possible. + +mapsector currently has support for the following mapping schemes: + +EOF + for mapper in $mappers; do + describe_$mapper + done + cat </dev/null | awk -F '[ ,]+' '{print "(" $5 ", " $6 ")"}' -} - -dmcryptmap() -{ - devnums="`deviceid $1`" - - dmsetup ls --target crypt | awk '{print $1}' | while read dmdev; do - if dmsetup deps $dmdev | grep -qF "$devnums"; then - echo "/dev/mapper/$dmdev" - fi - done -} - -########################################################################### - -# Map device/sector through blockdevice mappings (e.g. lvm) - -map() -{ - while true; do - if detect_raid; then - echo "# $device: Raid detected" 1>&2 - map_raid - elif detect_partition; then - echo "# $device: partition table detected" 1>&2 - map_partition - elif detect_crypt; then - echo "# $device: LUKS/cryptsetup detected" 1>&2 - map_crypt - elif detect_lvm; then - echo "# $device: LVM detected" 1>&2 - map_lvm - else - break - fi - done -} - -######################################## -#### Partitions - -detect_partition() -{ - [ -z "`fdisk -l $device 2>&1 >/dev/null`" ] -} - -map_partition() -{ - # Step 1: Find partition to which this sector belongs - - local partdev - local partstart - local partsector - - partdev="`fdisk -ul $device | awk -v sector="$sector" -F '[ *]+' '/^\// && !/Extended$/ && $2<=sector && $3>=sector {print $1,$2}'`" #`" - - if [ -z "$partdev" ]; then - echo "# sector $sector is not part of any partition on $device" 1>&2 - exit 0 - fi - - partstart="${partdev#* }" - partdev="${partdev% *}" - partsector="`dc -e "$sector $partstart - p"`" # `" - - echo "offset $partstart" - echo "device $partdev partition" - echo "sector $partsector" - - device="$partdev" - sector="$partsector" -} - -######################################## -#### LUKS / cryptsetup - -detect_crypt() -{ - which cryptsetup >/dev/null 2>&1 && [ -n "`dmcryptmap $device`" ] -} - -map_crypt() -{ - # Step 2: Find the crypted volume defined for this partition - - local offset - local devnums - local cryptdev - local cryptsector - local type - - offset="`cryptsetup luksDump $device 2>/dev/null | awk '/^Payload offset/{print $3}'`" - - if [ -z "$offset" ]; then - # Plain dmcrypt - offset=0 - type=dmcrypt - else - type=luks - fi - - cryptdev="`dmcryptmap $device`" - - if [ -z "$cryptdev" ]; then - echo "! Failed to find decrypted mapper device for $device" - exit 1; - fi - - cryptsector="`dc -e "$sector $offset - p"`" #`" - - echo "offset $offset" - echo "device $cryptdev crypt" - echo "type $type" - echo "sector $cryptsector" - - device="$cryptdev" - sector="$cryptsector" -} - -######################################## -#### LVM - -detect_lvm() -{ - which pvdisplay >/dev/null 2>&1 && pvdisplay $device >/dev/null 2>&1 -} - -map_lvm() -{ - local pvname - local pesize - local vgname - local pestart - local penum - local subsector - local lestart - local firstpe - local lenum - local fsdev - local fssector - - # Step 3: Get pysical extent number - - pvname="`pvdisplay -c $device 2>/dev/null | awk -F: '{print $1,$2,$8}' | sed -e 's/^ *//'`" - - if [ -z "$pvname" ]; then - echo "! $device is not a physical volume" 1>&2 - exit 1 - fi - - pesize="${pvname##* }" - vgname="${pvname% *}" - pvname="${vgname% *}" - vgname="${vgname#* }" - pesize="`dc -e "$pesize 2 * p"`" #`" - pestart="`pvs --unit s -ope_start $device 2>/dev/null | sed -n -e 's/ *//g' -e 's/S.*$//' -e '$p'`" - penum="`dc -e "$sector $pestart - $pesize ~ n [ ] n p"`" #`" - subsector="${penum% *}" - penum="${penum#* }" - - echo "device $pvname pv" - echo "offset $pestart" - echo "pesize $pesize" - echo "extent $penum" - echo "subsector $subsector" - echo "group $vgname" - - # Step 4: Find associated logical volume - - lestart="$(vgdisplay -v $vgname 2>/dev/null | awk '/LV Name/{print $3}' | while read lvname; do \ - lvdisplay -m $lvname 2>/dev/null \ - | awk -v RS="\n *\n( --- Segments ---\n)?" \ - -F"[ \t\n:]+" \ - -v pvname="$pvname" \ - -v penum="$penum" \ - -v lvname="$lvname" \ - '$0 ~ "Physical volume[ \t]+" pvname && $14<=penum && $16>=penum{print lvname,$4,$14}'; \ - done)" - - if [ -z "$lestart" ]; then - echo "# pysical extent $penum of $pvname is not mapped in any logical volume" 1>&2 - exit 0 - fi - - lvname="${lestart%% *}" - lestart="${lestart#* }" - firstpe="${lestart#* }" - lestart="${lestart% *}" - lenum="`dc -e "$penum $firstpe - $lestart + p"`" #`" - - echo "device $lvname lv" - echo "extent $lenum" - - fsdev="$lvname" - fssector="`dc -e "$lenum $pesize * $subsector + p"`" #`" - - echo "sector $fssector" - - device="$fsdev" - sector="$fssector" -} - -######################################## -#### Raid-1 - -detect_raid() -{ - which mdadm >/dev/null 2>&1 && mdadm -Q $device | grep -qF -- "--examine" -} - -map_raid() -{ - local mddevice - local mdlevel - - mddevice="`mdadm -Q $device | sed -ne 's/.*\(raid[0-9] \/dev\/[^.]*\).*/\1/' -eT -ep`" - - if [ -z "$mddevice" ]; then - echo "! raid master device for raid componentn device $device not found" 1>&2 - exit 1 - fi - - mdlevel="${mddevice% *}" - mddevice="${mddevice#* }" - - echo "device $mddevice md" - echo "raidlevel $mdlevel" - echo "sector $sector" - - device="$mddevice" -} - -########################################################################### - -# Scan the final blockdevice for additional information. -# Information includes mountpoint, filesystem type and filesystem type -# specific information: filesysetm block, inode number and filename - -scan() -{ - scan_mountpoint - if detect_ext2fs; then - echo "# $device: ext2/3/4 filesystem detected" 1>&2 - scan_ext2fs - elif detect_reiserfs; then - echo "# $device: reiserfs filesystem detected" 1>&2 - scan_reiserfs - fi -} - -######################################## -#### Mountpoint - -scan_mountpoint() -{ - local devnums - devnums="`deviceid $device`" - - # Step 5: Find filesystem mount point - - while read dev dir opts; do - case "$dev" in - *:*) ;; - *) - if [ "$devnums" == "`deviceid $dev`" ]; then - echo "mountpoint $dir" - break - fi - ;; - esac - done < /proc/mounts -} - -######################################## -#### ext2/ext3 - -detect_ext2fs() -{ - which tune2fs >/dev/null 2>&1 && tune2fs -l $device >/dev/null 2>&1 -} - -scan_ext2fs() -{ - local fsblocksize - local fsblock - local fssubsector - local fstype - local inode - - fstype="`file -s $device | sed -e 's/.*\(ext[0-9]\).*/\1/'`" - echo "fstype $fstype" - - # Step 6: Get filesystem blocksize and convert sector number to filesystem block number - - fsblocksize="`tune2fs -l $device | awk '/Block size/{print $3/512}'`" - - if [ -z "$fsblocksize" ]; then - echo "! $device is not ext2/ext3" 1>&2 - exit 1 - fi - - fsblock="`dc -e "$sector $fsblocksize ~ n [ ] n p"`" #`" - fssubsector="${fsblock% *}" - fsblock="${fsblock#* }" - - echo "blocksize $fsblocksize" - echo "block $fsblock" - echo "subsector $fssubsector" - - # Step 7: Check, whether block is in use - - if echo "testb $fsblock" | debugfs $device 2>/dev/null | grep -qF "not in use"; then - echo "blockstate free" - exit 0 - fi - echo "blockstate used" - - # Step 8: Find inode, to which the block belongs - - inode="`echo "icheck $fsblock" | debugfs $device 2>/dev/null | awk 'FNR>1{print $2}'`" #`" - - if [ -z "$inode" ]; then - echo "blocktype meta?" - exit 0 - fi - - echo "inode $inode" - - # Step 9: Find file name(s) referencing the inode - - ( - namefound="$(\ - echo "ncheck $inode" \ - | debugfs $device 2>/dev/null \ - | sed -e '1d' -e 's/^[0-9]*[ ]*//' -e 's/^\/\//\//' \ - | while read name; do \ - if [ -z "$firstname" ]; then \ - echo "blocktype data" 1>&3; \ - echo "1"; \ - firstname=1; \ - fi; \ - echo "name $name" 1>&3; \ - done \ - )" - if [ -z "$namefound" ]; then - echo "blocktype journal?" - fi - ) 3>&1 -} - -######################################## -#### Reiser-FS - -detect_reiserfs() -{ - which debugreiserfs >/dev/null 2>&1 && debugreiserfs $device >/dev/null 2>&1 -} - -scan_reiserfs() -{ - local blocksize - local block - local subsector - - echo "fstype reiserfs" - - # Step 6: Get filesystem blocksize and convert sector number to filesystem block number - - blocksize="`debugreiserfs $device 2>/dev/null | awk '/^Blocksize:/{print $2/512}'`" - - if [ -z "$blocksize" ]; then - echo "! $device is not reiserfs" 1>&2 - exit 1 - fi - - block="`dc -e "$sector $blocksize ~ n [ ] n p"`" #`" - subsector="${block% *}" - block="${block#* }" - - echo "blocksize $blocksize" - echo "block $block" - echo "subsector $subsector" - - # Step 7: Check, whether block is in use - - if debugreiserfs -1 $block $device 2>&1 >/dev/null | grep -qF "free in ondisk bitmap"; then - echo "blockstate free" - exit 0 - fi - echo "blockstate used" - - # Use debugreiserfs -1 to check the block type. This however only works if the block is readable. - type="`debugreiserfs -1 $block $device 2>/dev/null | sed -e '/^=*$/d' | head -1`" - - case "$type" in - "Looks like unformatted") type="data" ;; - "Reiserfs super block"*) type="superblock" ;; - "LEAF NODE"*) type="meta" ;; - "INTERNAL NODE"*) type="meta" ;; - "Desc block"*) type="journal" ;; - *) type="" ;; - esac - - if [ -n "$type" ]; then - echo "blocktype $type" - fi - - # Step 8: Find object id to which this block belongs - # Step 9: Find file name(s) referencing this object id - - # Currently we only look for $block in indirect blocks. - - python - $device $block </dev/null" % device) - -def parse_leafnode(): - global fp - l = fp.readline() - #sys.stderr.write("> leafnode(1): %s\n" % repr(l)) - if not l.startswith("LEAF NODE") : return - for i in range(4) : fp.readline() - while True: - l = fp.readline() - #sys.stderr.write("> leafnode(2): %s\n" % repr(l)) - parts = l.split("|") - if len(parts)<2 : return - parts = parts[2].split() - if len(parts)<4 : return - obid=(int(parts[0]),int(parts[1])) - if parts[3] == "DIR" : parse_dir(obid) - elif parts[3] == "IND" : parse_indirect(obid) - else: - while True: - l = fp.readline().strip() - #sys.stderr.write("> leafnode(3): %s\n" % repr(l)) - if l == 79*"-" or l == 67*"=" : break - -def parse_dir(obid): - global fp - global dirtree - fp.readline() - while True: - try: - l = fp.readline().rstrip() - #sys.stderr.write("> dir: %s\n" % repr(l)) - if l == 79*"-" or l == 67*"=": return - if l.endswith("not set"): continue - i = l.index("\"(") - name = l[6:6+int(l[i+2:i+5])] - if name == "." or name == ".." : continue - i = l.index("[",len(name)+12) - entryid = tuple(map(int,l[i+1:l.index("]",i+1)].split())) - entry = dirtree.get(entryid) - if entry is None : entry = dirtree[entryid] = set() - entry.add((name,obid)) - except ValueError: - pass - -def parse_indirect(obid): - global fp - global blocknr - global blockid - fp.readline() - for pointer in fp.readline().strip()[1:-1].split(): - i = pointer.find("(") - if i == -1: - blkmin = blkmax = int(pointer) - else: - blkmin = int(pointer[:i]) - blkmax = blkmin+int(pointer[i+1:-1])-1 - if blocknr >= blkmin and blocknr <= blkmax: - blockid = obid - fp.readline() - -def scan_path(id): - global dirtree - entry = dirtree.get(id) - #sys.stderr.write("> scan_path: %s->%s\n" % (id, entry)) - if entry is None: - return [ '/' ] - else: - rv = [] - for name, parent in entry: - for path in scan_path(parent): - rv.append(os.path.join(path,name)) - return rv - -def parse(): - global fp - while True: - while True: - l = fp.readline() - #sys.stderr.write("> parse: %s\n" % repr(l)) - if not(l) : return - if l.strip() == 67*"=" : break - parse_leafnode() - -parse() - -if blockid is None: - sys.exit(0) - -sys.stdout.write("objectid %d %d\n" % blockid) - -for path in scan_path(blockid): - if path != '/': - sys.stdout.write("name %s\n" % path) -EOF - -} - -########################################################################### - -unset LANG - -noscan="" -if [ "$1" == "--noscan" ]; then - noscan=1 - shift -fi - -if [ -z "$2" ]; then - cat < " - -mapsector -- Map sector numbers to file name(s) - -Given a device and a sector number, mapsector will try to find the -file name(s) mapping to this sector. It will try to gather as much -information about the given sector as possible. - -mapsector currently has support for the following mapping schemes: - - partition table - RAID-1 - cryptsetup (luks and plain dmcrypt) - LVM in linear allocation mode - -mapsector currently supports the following filesystems - - ext2/3/4 - reiserfs - -mapsector will try it's best to find an associated file name but -depending on the filesystem state and the type of sector (e.g. if -the sector is part of a filesystem metadata block) this may not be -possible. - -For mapsector to work, the filesystem must be currently active -(e.g. LVM must be running, crypted devices must have been set up). The -filesystem must not necessarily be mounted (though if mounted, -mapsector will give you the mountpoint). - -if '--noscan' is given, the possibly lengthy (!!) filesystem scan for -filenames is skipped. -EOF - exit 1 -fi - -device="$1" -sector="$2" - -echo "device $device" -echo "sector $sector" - -map -if [ -z "$noscan" ]; then - scan -fi