A Cautionary Tale

Here’s a cautionary tale for all you folks.

So I was going along, happily minding my own business, debianizing/defenestrating a few new computers, when I needed to make root/rescue disks. I went to my laptop, got the dd images and typed:

dd if=root.bin of=/dev/hda bs=1024 conv=sync

Boom. That was fast. And the floppy didn’t even spin. Hm…

Now wait a minute—that’s /dev/hda, not /dev/fd0! That’s ME. But I wasn’t root???

 ~> ls -l /dev/hda brw-rw---- 1 root disk 3, 0 Mar 14 2002 /dev/hda ~> groups ...disk... 

Uh oh. I suddenly have the feeling of someone you see in the movies where the torso has been severed but they don’t feel it yet. I just overwrote the first 1024K of my hard drive with root.bin.

But everything was still working fine, for the moment. I had overwritten my partition table and part of my hibernation partition, but none of my actual linux drive.

So I foundered about for a bit, desperately not wanting to have to back up my whole drive and start over. I called my friend Dylan, woke him up (you never know with mathematicians!), and he gave me some very good ideas.

It turns out my partition table was still in memory, in /proc/partitions.

cfdisk /dev/hda failed (fatal error), but it turns out I could still run fdisk /dev/hda.

So I manually recreated the partition table with fdisk from /proc/partitions (set the partition types), wrote it to disk, reinstalled grub, rebooted and crossed my fingers.

Back to normal!

Try recovering from such a disaster under Windows, and I’ll see you next year.

A few lessons to be learned:

  • Don’t put yourself in group disk! This might be obvious to some of you, but I had added myself in order to burn CDs (I should have created a different group, didn’t think about it at the time).
  • Save a copy of your partition table! I was lucky based on what I did that the partition table was still in /proc, but googling suggested that this is sometimes an invaluable recovery tool. Put your partition table somewhere else. There is a tool gpart that tries to guess your partition table based on the data, but having the information just makes it so much easier.
  • Don’t dd over your hard drive.

I guess that’s it. I hope my averted disaster is helpful to some of you.

fetchemusic

Unfortunately, this script no longer works. EMusic has switched to an encrypted RMP format. I’m leaving this script here in case it is ever useful for another project.

Update 10/1/03: Someone has written a very nice perl script that works with the new encrypted EMP file format, called decrypt-emp. Get it now!

 #!/usr/bin/perl # fetchrmp.pl - a quick-n-dirty script for parsing EMusic RMP data and # fetching entire albums. Requires an EMusic.com subscription. :-) # AUTHOR: Doran Barton  # Modifications: Adam Kessel  # VERSION 0.9 # Copyright (c) 2002 Doran Barton. All rights reserved. # Copyright (c) 2003 Adam Kessel. All rights reserved. # This program is free software; you can distribute it and/or modify it # under the same terms as Perl itself. my $VERSION = 0.91; use strict; use XML::EasyOBJ; use LWP::Simple; use Getopt::Long; use File::Path; use File::Copy; Getopt::Long::config("no_ignore_case"); my ($opt_help, $opt_destdir, $opt_rmpfile, $opt_folders, $opt_play, $opt_art); my $error = &GetOptions('help' => \$opt_help, 'destdir:s' => \$opt_destdir, 'rmpfile:s' => \$opt_rmpfile, 'folders' => \$opt_folders, 'art' => \$opt_art, 'play:s' => \$opt_play); if($opt_help) { exit _usage(); } if(!$opt_rmpfile) { print STDERR "ERROR: An RMP data file is required (with the --rmpfile parameter)\n\n"; exit _usage(); } if(!$opt_destdir) { $opt_destdir = "."; } if(defined $opt_play) { unless ($opt_play) { $opt_play = 'mpg321 -o oss'; } } $opt_destdir =~ s</$><>; # Trim any trailing /'s from destination dir my $doc = new XML::EasyOBJ($opt_rmpfile); my $server = $doc->SERVER(0)->NETNAME(0)->getString; my @elements = $doc->TRACKLIST(0)->TRACK; my $track_num = 1; my ($track, $url, $track_number, $genre, $artist, $album, $current_track); my ($album_art, $lowergenre, $lowerartist, $loweralbum); foreach $track (@elements) { $url = sprintf("http://%s/%s/%s", $server, $track->TRACKID->getString, $track->FILENAME->getString); $current_track = $track->FILENAME->getString; $current_track =~ tr/A-Z /a-z_/; $current_track =~ s/[^a-z0-9_\-\.]//g; print STDERR "Getting ", $current_track, "... "; if ($opt_folders or $opt_art) { $genre = $track->GENRE->getString || ""; $artist = $track->ARTIST->getString || ""; $album = $track->ALBUM->getString || ""; $album_art = $track->ALBUMART->getString || ""; $loweralbum = $album; $loweralbum =~ tr/A-Z /a-z_/; $loweralbum =~ s/[^a-z0-9_\-]//g; $album =~ tr/ /_/; $album =~ s/[^A-Za-z0-9_\-]//g; $lowergenre = $genre; $lowergenre =~ tr/A-Z /a-z_/; $lowergenre =~ s/:.*//; $lowergenre =~ s/[^a-z0-9_\-]//g; $lowerartist = $artist; $lowerartist =~ tr/A-Z /a-z_/; $lowerartist =~ s/[^a-z0-9_\-]//g; $artist =~ tr/ /_/; $artist =~ s/[^A-Za-z0-9_\-]//g; $track_number = $track_num++; $track_number =~ s/^(\d)$/0$1/; } my $rv = getstore($url, $current_track); if($rv == 200) { print STDERR "OK\n"; if ($opt_folders) { mkpath("$opt_destdir/$lowergenre/$lowerartist/$loweralbum"); move($current_track,"$opt_destdir/$lowergenre/$lowerartist/$loweralbum/$artist---$album---$track_number---$current_track"); } } else { print STDERR "FAILED\n"; } } if ($opt_art) { if ($album_art) { my $rv = getstore($album_art,"$loweralbum.jpg"); if($rv == 200) { print STDERR "Art download OK\n"; if ($opt_folders) { move("$loweralbum.jpg","$opt_destdir/$lowergenre/$lowerartist/$loweralbum"); } } else { print STDERR "Art download failed\n"; } } } if ($opt_play) { if ($opt_folders) { chdir "$opt_destdir/$lowergenre/$lowerartist/$loweralbum"; } `$opt_play *mp3`; } sub _usage { print STDERR "This is $0 version $VERSION\n", "Usage: $0 --help \n", " or: $0 [--destdir DIR] --rmpfile FILE [--folders] [--play [mpeg player]] [--art]\n\n", "--folders puts track in folder hierarchy based on genre, album, and artist under destdir (or current directory if not specified)\n", "--play plays music when done downloading with specified command line (or mpg321 -o oss if not specified)\n", "--art downloads the album art if available and places it with the music\n\n", "Copyright (c) 2002 Doran Barton. All rights reserved. Modifications copyright (c) 2003 Adam Kessel.\n", "This program is free software; you can distribute it and/or modify it\n", "under the same terms as Perl itself.\n"; return 1; } 

syntax highlighted by Code2HTML, v. 0.9.1