Saturday, April 24, 2010

Reanimating My Lacie NAS Drive

So the other night I was doing my normal "computer stuff" and I noticed my 250GB "ED mini" Lacie NAS drive disappear from the network. I got up and wandered over to investigate, only to discover the dang thing was not powered on. And any attempts to power it on were futile. I tried a second Lacie power supply I had (just in case the PS was the problem), but no dice. No LED when I tried to turn it on, no nothin'. Considering my last backup had been 6 months ago, I had a vested interest in recovering the data if I could. Because the LED wasn't even coming on, I wondered if something in the internal circuitry (i.e. not the hard drive) may be failing. So I voided the warranty and opened the bad boy up (I had reached a point where I had nothing to lose).

Inside was a little board that the Hitachi Desk Star (sigh) IDE drive connects to, which had a PPC-based MPC6200 processor on it. I pulled the drive and put it in an external enclosure. When I connected it to my Windows XP system, the system claimed to have found 2 FAT partitions, but that neither were properly formatted. Declining the offer from Windows to "help a brother out" and format my partitions, I opted to start up my Fedora 9 VMWare image and connect the driver to it.

Linux FTW: a run of fdisk showed one small and one very large FAT-labeled primary partitions on the drive, and some extended partitions as well. One of these extended partitions contained the Linux base filesystem (busybox-based goodness) and the other contained the /etc and /var directories. A quick check of the /var/log/messages showed their drive is running a 2.4 kernel:

May 26 11:12:45 (none) user.warn kernel: Linux version 2.4.25-lacie6 (bertrand@neo.lacie.com) (gcc version 3.2.2 20030217 (Yellow Dog Linux 3.0 3.2.2-2a_1)) #1 mer jun 8 18:54:39 CEST 2005
Scanning the /etc/mtab file, I found the "user data" partition is recognized as a vfat format when the Lacie system mounts it:

/dev/loop0 /home vfat umask=002,gid=100 0 0
However, if I attempted a mount command to mount the large, user data parition, it would fail with an error telling me the partitions isn't a valid vfat format. Bah! I want my data! >:(

A bit more poking around revealed a startup script, appropriately named /etc/init.d/userdata, that is responsible for mounting the user data for the Lacie system to access it. Specifically, these lines of the script handle that functionality
output "Starting UserData service"
eval `edmini_interface partition userdata offset`
losetup $LOOP_DEV $HD_DEV -o $USERDATAPARTOFFSET
mount -o umask=002,gid=100 $LOOP_DEV $USERDATA_MP 2> /dev/null
These lines also reveal that the Lacie system isn't simply mounting the partition as one usually does, they are mounting it *at an offset* from the beginning of the partition. The losetup command is creating a loopback device for the user data partition that starts at an offset of USERDATAPARTOFFSET bytes into the partition, and the mount command these uses the new loopback device as the mountpoint. But what is that offset??? From examination of the startup scripts on the drive, I concluded that edmini_interface is used to give specific information about the device (like users and network setting) and where certain things can be located, such as the mysterious offset to the user data. A quick file /usr/bin/edmini_interface revealed it was a binary, and compiled for PPC, of course (dashing my hopes of it being an easy-to-understand script).

So I wrote the following script to brute force, in a lame sense of the term, the offset for me:


#!/bin/bash

OFFSET=0

while [ $((OFFSET < 50000000)) -eq 1 ]
do
LODEV=$(losetup -f)
losetup ${LODEV} /dev/sdc3 -o ${OFFSET}
echo "Attempt to mount ${LODEV} at device offset ${OFFSET}..."
mount -o ro ${LODEV} /mnt/pb2
RETVAL=${?}
[ "${RETVAL}" = "0" ] && echo "MOUNTED IT!!!" && exit 0
losetup -d ${LODEV}
OFFSET=$((OFFSET + 1))
done
This script sets up a loop to attempt to mount the partition, starting at the first byte (offset 0) until it finally succeeds with the mount command or has reached 50MB into the partition (yes, that's a bit ridiculously large, I admit it). The loop of execution does the following things in this order:
  1. Create a loopback device using the losetup -f command.
  2. Set the new loopback device to use the user data partition (in my case, /dev/sdc3 was what Fedora 9 assigned to it), again using the losetup command.
  3. Attempt to mount the new loopback device (as read-only) using the mount command.
  4. Save the return code from the mount command in RETVAL.
  5. If RETVAL indicates success (i.e. equals 0), then we're exit the loop, which leaves the user data partition mounted for you to go access.
  6. Otherwise, delete the loopback device (using losetup -d) , increment the offset by 1 byte, and try it again.
In my case, the script successfully mounted the partition when it got to offset 32256. This means I can mount and unmount my user data partition using the following commands:
losetup /dev/loop0 /dev/sdc3 -o 32256
mount -o ro /dev/loop0 /mnt/pb2
umount /mnt/pb2
losetup -d /dev/loop0
So why would Lacie mount past the first 32256 bytes of the partition? Apparently to store data for their own purposes. For grins, I used dd to dump this data:
[root@localhost ~]# dd if=/dev/sdb3 bs=1 count=32256|hexdump -C
00000000 33 c0 8e d0 bc 00 7c fb 50 07 50 1f fc be 1b 7c |3.....|.P.P....||
00000010 bf 1b 06 50 57 b9 e5 01 f3 a4 cb be be 07 b1 04 |...PW...........|
00000020 38 2c 7c 09 75 15 83 c6 10 e2 f5 cd 18 8b 14 8b |8,|.u...........|
00000030 ee 83 c6 10 49 74 16 38 2c 74 f6 be 10 07 4e ac |....It.8,t....N.|
00000040 3c 00 74 fa bb 07 00 b4 0e cd 10 eb f2 89 46 25 |<.t...........F%|
00000050 96 8a 46 04 b4 06 3c 0e 74 11 b4 0b 3c 0c 74 05 |..F...<.t...<.t.|
00000060 3a c4 75 2b 40 c6 46 25 06 75 24 bb aa 55 50 b4 |:.u+@.F%.u$..UP.|
00000070 41 cd 13 58 72 16 81 fb 55 aa 75 10 f6 c1 01 74 |A..Xr...U.u....t|
00000080 0b 8a e0 88 56 24 c7 06 a1 06 eb 1e 88 66 04 bf |....V$.......f..|
00000090 0a 00 b8 01 02 8b dc 33 c9 83 ff 05 7f 03 8b 4e |.......3.......N|
000000a0 25 03 4e 02 cd 13 72 29 be 46 07 81 3e fe 7d 55 |%.N...r).F..>.}U|
000000b0 aa 74 5a 83 ef 05 7f da 85 f6 75 83 be 27 07 eb |.tZ.......u..'..|
000000c0 8a 98 91 52 99 03 46 08 13 56 0a e8 12 00 5a eb |...R..F..V....Z.|
000000d0 d5 4f 74 e4 33 c0 cd 13 eb b8 00 00 80 38 46 08 |.Ot.3........8F.|
000000e0 56 33 f6 56 56 52 50 06 53 51 be 10 00 56 8b f4 |V3.VVRP.SQ...V..|
000000f0 50 52 b8 00 42 8a 56 24 cd 13 5a 58 8d 64 10 72 |PR..B.V$..ZX.d.r|
00000100 0a 40 75 01 42 80 c7 02 e2 f7 f8 5e c3 eb 74 49 |.@u.B......^..tI|
00000110 6e 76 61 6c 69 64 20 70 61 72 74 69 74 69 6f 6e |nvalid partition|
00000120 20 74 61 62 6c 65 00 45 72 72 6f 72 20 6c 6f 61 | table.Error loa|
00000130 64 69 6e 67 20 6f 70 65 72 61 74 69 6e 67 20 73 |ding operating s|
00000140 79 73 74 65 6d 00 4d 69 73 73 69 6e 67 20 6f 70 |ystem.Missing op|
00000150 65 72 61 74 69 6e 67 20 73 79 73 74 65 6d 00 00 |erating system..|
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000180 00 00 00 8b fc 1e 57 8b f5 cb 00 00 00 00 00 00 |......W.........|
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001b0 00 00 00 00 00 00 00 00 45 4c 44 32 00 00 80 01 |........ELD2....|
000001c0 01 00 0c fe ff ff 3f 00 00 00 12 81 10 1d 00 00 |......?.........|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
32256+0 records in
32256+0 records out
00007e00
32256 bytes (32 kB) copied, 0.906831 s, 35.6 kB/s
I noticed the value at offset 0x000001c6 is 0x3f00, which is exactly 32256/2, so this *could* be a halfword index to the start of the user data. The error strings in that space appear to be the kind you'd get from the bootloader (which this could conceivably be, even though no partition is explicitly marked as 'boot' on the drive). At this point, I stopped looking at it since I had achieved my main goal of getting my data back. Huzzah!