Raspberry Pi Pinout Diagram

Pinouts for the Raspberry Pi P1 header, showing pins that can be used for general purpose IO. I used some online sources to get the naming for the pins (source list at the bottom of this post). Some of the power and ground pins were initially marked as ‘do not connect’, but it has now been confirmed that these pins won’t change so I included them below as well (Pins 4, 9, 14, 17, 20 and 25).

A few pins changed between Revision 1 and Revision 2 of the board (Pins 3, 5 and 13). The pin description in the table below shows first the Revision 1 GPIO number followed by a slash and then the Revision 2 GPIO number.

Raspberry Pi Pinout Diagram

Raspberry Pi Pinout Diagram showing P1 header orientation

 

Name Pin Pin Name
3.3 V 1 orange red 2 5 V
GPIO 0 / 2 I2C SDA 3 cyan red 4 5 V
GPIO 1 / 3 I2C SCL 5 cyan black 6 GND
GPIO 4 7 green yellow 8 GPIO 14 UART TXD
GND 9 black yellow 10 GPIO 15 UART RXD
GPIO 17 11 green green 12 GPIO 18
GPIO 21 / 27 13 green black 14 GND
GPIO 22 15 green green 16 GPIO 23
3.3 V 17 orange green 18 GPIO 24
GPIO 10 SPI MOSI 19 magenta black 20 GND
GPIO 9 SPI MISO 21 magenta green 22 GPIO 25
GPIO 11 SPI SCLK 23 magenta magenta 24 GPIO 8 SPI CE0
GND 25 black magenta 26 GPIO 7 SPI CE1

If you would like to use the graphics in the diagram you can download the source vector file in SVG format from GitHub.

Sources used to create this post:

Raspberry Pi and Arduino via GPIO UART

In an attempt to get my Raspberry Pi talking to my Arduino I’m exploring various different options. The first was to just use the USB connection, but that was too simple. So, here is how to connect the two using the UART on the GPIO pins of the Raspberry Pi.

To make testing easier I wanted to keep the Arduino’s serial connected via USB to my PC so I can print messages there and read it with the Serial Monitor. This meant using the SoftSerial library to implement a second serial port to talk to the Raspberry Pi. To protect my Raspberry Pi and to convert the 5V of the Arduino to 3.3V the Raspberry Pi needs I used a CD4050.

To show how this works the Arduino is running a small program that reads from the Raspberry Pi’s and copies this to my PC via USB.

By default the Raspberry Pi uses the UART in two ways:

  1. Console Messages (including bootup messages)
  2. A getty so you can login via serial

To use this serial port for your own uses you need to disable these two services. I decided to leave them enabled to test how well the serial connection works. However, the SoftSerial library on the Arduino doesn’t work so well at the default baudrate of 115200, so I changed this on the Raspberry Pi to 9600:

To change the console baudrate, edit /boot/cmdline.txt to look like this (this is all one line):

dwc_otg.lpm_enable=0 console=ttyAMA0,9600 kgdboc=ttyAMA0,9600 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

Also, edit /etc/inittab to change the baudrate of the getty (you should fine a line like this with the baudrate of 115200, change that number to 9600):

2:23:respawn:/sbin/getty -L ttyAMA0 9600 vt100

Ok, now upload the program to your Arduino:

 

/*

 Connects Arduino to Raspberry Pi
 Arduino: SoftSerial
 Raspberry Pi: GPIO UART

 This is just a simple passthrough, based on Arduino SoftSerial example

 */
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX

void setup()  
{
 // Open serial communications to PC and wait for port to open:
  Serial.begin(57600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  Serial.println("Connected to PC");

  // set the data rate for the SoftwareSerial port to Raspberry Pi
  mySerial.begin(9600);
}

void loop() // run over and over
{
  // If data is available on Raspberry Pi, print it to PC
  if (mySerial.available())
    Serial.write(mySerial.read());
  // If data is available on PC, print it to Raspberry Pi
  if (Serial.available())
    mySerial.write(Serial.read());
}

Connect the Arduino to the Raspberry Pi:

Raspberry Pi Pins used:

  • 1 : 3.3V
  • 6 : Ground
  • 8 : UART TXD
  • 10: UART RXD
CD4050 Pins used:

  • 1 : VDD (3.3V)
  • 2 : Output A
  • 3 : Input A
  • 4 : Output B
  • 5 : Input B
  • 8 : VSS (Ground)

If you then open your Serial Monitor on you PC, and set the baudrate to 57600 you should get the following message:

Connected to PC

If you then reboot your Raspberry Pi, the console messages should be echoed back to the Serial Monitor running your PC and leave you with a login prompt from the getty:

If you change ‘No Line Ending’ to ‘Newline’ you can enter your username and are then prompted for a password. Unfortunately the password doesn’t work. I still need to figure out why it’s not accepting my password. I suspect it’s to do with a line termination character or something.

Next step to connect this with a Serial library on the Raspberry Pi to talk to the Arduino. Maybe using pySerial like Dr Monk did in his Raspberry Pi and Arduino project. You should be able to use this in exactly the same way after disabling the console and getty and using ttyAMA0 as the serial port.

 

Arduino Web Enabled Aquarium Controller

This is a project I started a few months ago, but never finished. I got distracted by the Raspberry Pi :). Even though it is unfinished maybe someone could get some value out of the current state of the project.

The idea was to create a controller for an aquarium, to measure temperature, measure water level and to turn pumps, heaters and lights on/off based on measurements and times. And, to have a web enabled interface to the controller.

In it’s current state the controller works with DS18B20 temperature sensors and displays the temperature on a webpage. The web server runs on the arduino and uses a combination of generated html and static html stored on an SD card in the ethernet shield.

Scroll down to the bottom of this post to find the download link for the project.

Hardware used:

  • Arduino Mega2560
  • Arduino Ethernet Shield
  • DS18B20 temperature sensors

I also have the following hardware, but never got around to adding to the project:

  • DS1307 Real Time Clock
  • Relay modules

Arduino Aquarium Hardware

And here are a few screenshots of the program running on the arduino with 5 temperature sensors. The temperature sensors all connect to the same pin, and the ‘Scan’ button scans for probes and sets their resolution. The ‘Temperature’ button then reports the temperature for each of the probes.

And this page shows that other dynamic data can also be added. In this case it shows the current values of the Analog input pins.

To build this project you will need the Arduino Mega2560 (an Uno might work, have not tested that), Ethernet Shield, MicroSD card, one or more DS18B20 temperature sensors and a 5K resistor.

You can download the Arduino project here:

Also included in the download is the stylesheet. On your SD card (which goes into your Ethernet Shield), create a www directory and place the style.css file in there.

This project started out on the Marine Aquarium South Africa (MASA) forums, you might be able to pick up some more information in the thread over there: http://www.marineaquariumsa.com/showthread.php?t=32489

Ordering a Raspberry Pi

I’ve had a few people ask me how I ordered my Raspberry Pi and how long it took for me to get it. So here is the process I followed, including a time line.

I live in Cape Town, South Africa and the whole process took about 4 months from registration to delivery.

1 March 2012 : Registration

I registered my interest on the RS Components website ( http://uk.rs-online.com/web/generalDisplay.html?id=raspberrypi ) and received an email confirming my registration:

15 March 2012 : Update

I received an update from RS Components that they’ve had a ‘manufacturing hiccup’ but not to worry, and that invitation will still be sent out on a first-come, first served basis based on when I registered.

8 May 2012 : Update #2

I receive another update from RS Components. They say that they’ve invited the next 4000 people in the queue to order their Raspberry Pi’s and that the second batch of boards are on their way.

28 May 2012 : Time to order

I get an email from RS Components saying I can now place my order. This takes me to a webpage where I can enter my activation code included in the email and allows me to order the Raspberry Pi and pay for it.

I received an order confirmation back, with an expected dispatch of 4 weeks:

27 June 2012 : DHL Shipment Notification

I receive an email from DHL indicating that my order has shipped with DHL Express, including a tracking number and tracking URL for my package.

DHL Tracking page shows me when the package leaves from London to arrive in Cape Town:

29 June 2012 : Raspberry Package arrives

Finally, my Raspberry Pi arrives!

It was in a bubble envelope package, containing a small cardboard box:

And the cardboard box contained the Raspberri Pi inside an anti-static bag, wedged between two pieces of foam and two pamphlets:

Update (2012-07-17) : The one per customer limit has been raised, and you can now order as many as you like from this website: http://authenticate.rsdelivers.com/ when I had a look today the wait time was 11 weeks for delivery.

 Raspberry Pi is a trademark of the Raspberry Pi Foundation

Creating a dynamic image with PHP

To create a dynamic image is easy with PHP and the GD library. Its also a fun way to make your forum banner stand out by having it change each time someone loads it.

For example, I used to have the following forum signature while I was playing EverQuest II:

Forum Signature

Forum Signature

The image is created by a PHP page and the line at the bottom is randomly chosen from a list. Each time this page is reloaded, the message changes. The list of messages is actually from EverQuest I, messages that was shown in-game when you were zoning.

My example only uses text, but you can of course use graphics too. You could create a base image in a paint package and then use PHP to load that image and use it as a canvas to drop on instead of starting out with a blank background.

Here is the PHP I used to create this image:

<?php

# Andre Miller
# http://www.andremiller.net/
#

$v = array(
"Adding Randomly Mispeled Words Into Text...",
"Adding Vanilla Flavor to Ice Giants...",
"Always Frisky Kerrans <AFK>...",
"Attaching beards to dwarves...",
"Buy:LurN Tu Tok liK Da OgUr iN Ayt DaYz by OG...",
"Checking Anti-Camp Radius...",
"Creating randomly generated feature...",
"DING!...",
"Does Anyone Actually Read This?...",
"Doing things you dont wanna know about...",
"Dusting off spell books...",
"Ensuring Everything Works Perfektly...",
"Ensuring Gnomes are still short...",
"Filling Halflings With Pie...",
"Have You Hugged An Iksar Today?...",
"Have You Tried Batwing Crunchies Cereal?...",
"Hiding Catnip From Vah Shir...",
"Hitting Your Keyboard Won't Make This Faster...",
"If You Squeeze Dark Elves You Don't Get Wine...",
"Karnors..... over 40 billion trains served...",
"Loading, Don't Wait If You Don't Want To...",
"Loading useless information...",
"Loading velious textures...",
"Looking For Graphics <LFG>...",
"Looking Up Barbarian Kilts...",
"Look Out!!  Behind You...",
"Now Spawning Fippy_Darkpaw_432,326,312...",
"Oiling Clockworks...",
"Polishing erudite foreheads...",
"Preparing to Spin You Around Rapidly...",
"Refreshing Death Touch Ammunition...",
"Ruining My Own Lands...",
"Sanding Wood Elves - Now 37% smoother...",
"Searching High Elf Robes...",
"Sharpening Claws...",
"Sharpening Swords...",
"Spawning Your_Characters01...",
"Starching High Elf Robes...",
"Stringing Bows...",
"Stupidificationing Ogres...",
"Teaching Snakes to Kick...",
"Told You It Wasn't Made of Cheese...",
"Warning: Half Elves Are Now .49999 Elves...",
"Whacking Trolls With Ugly Stick...",
"You Have Gotten Better At Loading! (8)..."
);

$message = $v[rand(0, sizeof($v)-1)];
header ("Content-type: image/png");
$img_handle = ImageCreate (350, 60) or die ("Cannot Create image");
$back_color = ImageColorAllocate ($img_handle, 255, 255, 255);
imagecolortransparent ($img_handle, $back_color);
$color_1 = ImageColorAllocate ($img_handle, 255, 102, 51);
$color_2 = ImageColorAllocate ($img_handle, 1, 1, 1);
$color_3 = ImageColorAllocate ($img_handle, 51, 102, 255);
ImageLine($img_handle, 0, 1, 250, 1, $color_2);
ImageString ($img_handle, 2, 0,2, "Dalden - 70 Illusionist / 70 Provisioner", $color_1);
ImageString ($img_handle, 2, 0,12, "Leader of Aenigma (Guild level 49)", $color_1);
ImageString ($img_handle, 2, 0,22, "Euro-time guild on Crushbone", $color_1);
ImageString ($img_handle, 31, 0,35, "Loading Please Wait...", $color_2);
ImageString ($img_handle, 0, 0, 50, $message, $color_3);
ImagePng ($img_handle);
?>

To keep the image transparent, just make sure you don’t use $back_color for any of the text.

Save this php script on your server and use it as the URL of an image.

For example: <img src=”http://www.andremiller.net/projects/dynamic-php-image/dalden_banner.php”>

This will show up as an image in your browser:

Forum Signature

Forum Signature

Manual patching of EverQuest II

(Update, as pointed out in a comment below, since the new launcher, this method no longer works)

I don’t play EverQuest II anymore, but figured maybe someone else might find this useful as well.

Sometimes when using the patcher the download might get stuck on a certain file and in those cases it might be useful to manually download the file, either with your browser or with a download accellerator (such as Free Download Manager).

To download a file manually outside of the EverQuest II patcher you need the full URL of the file.

This is quite easy to find inside the update XML file kept on the SoE patch server. The patcher downloads this file each time you run it to check for updates, and you can do the same with your browser:

http://laeaberrpatch.everquest2.com:7010/patch/eq2/en/eq2-update.xml.gz

The file is compressed, on Windows you can use 7-Zip or WinRAR to open it. If you have a Linux box nearby, just use gzip.

You can open the XML file in any text editor to view its contents to locate the specific file you are interested in. Then follow the directory tree up to the top to find out what the full URL would be.

If you have a Linux system, you can also pass the XML file through xmllint to make it prettier:

xmllint --format eq2-update.xml > formatted.xml

If you open this XML in Internet Explorer you will get a nice tree view of the XML

Here is an example.

Say I want to download the file “Char_monsters.vpk”

I do a search in the file and find:

<File LocalName="Char_monsters.vpk" Compressed="false"
      TimeStamp="2009: 1:23:11:53:42" Name="Char_monsters.vpk"
      TotalSize="47130857" DownloadSize="47130857" CRC="1978781209 ">

I now go up the XML structure and find that this File tag was inside a Directory tag:

<Directory Name="paks">

So I know the file ends with paks/Char_monsters.vpk

If you go up further in the XML you find that this Directory tag is inside another Directory tag:

<Directory LocalPath="::HomeDirectory::" Name="."
           RemotePath="patch/eq2/en/patch0/main">

And that tells me where the file is on the server. The full path is now:

patch/eq2/en/patch0/main/paks/Char_monsters.vpk

Go up even further in the XML (now we are at the top) we find:

<Product Name="EverQuest 2" Server="laeaberrpatch.everquest2.com"
          Port="7010" AccessPath="patch/eq2/en/patch0"
          GzPath="/m2/http-docs/patch/stage/eq2/en" Version="568">

This tells us the server details, which we can now use to build the full URL:

http://laeaberrpatch.everquest2.com:7010/patch/eq2/en/patch0/main/paks/Char_monsters.vpk

This URL you can open in your browser to download the file manually.

Also note that some files are compressed on the server. If you find a file that ends in a .gz extension you need to use one of the compression utilities above to decompress it first before placing it in your EverQuest II directory.

Converting from Drupal 5.5 to WordPress 2.7.1

I finally decided to go ahead with the conversion from Drupal to WordPress. I don’ thave anything against Drupal, it just didn’t work for me.

Luckily for me my site wasn’t that big so I could do things like categories, tags and slugs manually. All I wanted to copy across were the actual articles and the comments.

I used parts of the SQL script that Dave Dash, D’Arcy Norman and Mike Smullin worked on and  made a few changes to suit my needs.

To convert the posts had to modify the script a bit because all my nodes in Drupal were of type story, not pages or posts, so I simply removed the where to clause.

# Use the Drupal database
use andremiller_drupal;
# Remove all current posts from WordPress
TRUNCATE TABLE andremiller_wordpress.wp_posts;
# Insert posts from Drupal into WordPress
INSERT INTO andremiller_wordpress.wp_posts (id, post_date, post_content, post_title, post_excerpt, post_name, post_modified, post_type, `post_status`)
SELECT DISTINCT
n.nid `id`,
FROM_UNIXTIME(n.created) `post_date`,
r.body `post_content`,
n.title `post_title`,
r.teaser `post_excerpt`,
IF(SUBSTR(a.dst, 11, 1) = '/', SUBSTR(a.dst, 12), a.dst) `post_name`,
FROM_UNIXTIME(n.changed) `post_modified`,
'post' `post_type`,
IF(n.status = 1, 'publish', 'private') `post_status`
FROM node n
INNER JOIN node_revisions r
USING(vid)
LEFT OUTER JOIN url_alias a
ON a.src = CONCAT('node/', n.nid)
;

That takes care of the posts. Comments are next.

On my drupal site the email address was not compulsory, so some comments did not have this field filled in. I made a small change here to generate a fake email if none was provided by concatenating the name and hostname of the poster together.

The threading option also didn’t work for me, but wasn’t too important, so I just made that a ’0′ to indicate no threading. In Drupal I was not using the approval feature, so the status of all my comments was set to ’0′. In WordPress that meant they all came in as unapproved. I updated the SQL so all the comments would be imported as approved.

 TRUNCATE TABLE andremiller_wordpress.wp_comments;
INSERT INTO andremiller_wordpress.wp_comments (comment_post_ID, comment_date, comment_date_gmt, comment_content, comment_parent, comment_author, comment_author_email, comment_author_url, comment_author_ip, comment_approved)
SELECT
nid,
FROM_UNIXTIME(timestamp),
FROM_UNIXTIME(timestamp),
comment,
0,
name,
IF(mail='', CONCAT(REPLACE(LOWER(name),' ', ''), '@', hostname, '.localhost'), mail),
homepage,
hostname,
1
FROM comments;
# update comments count on wp_posts table
UPDATE andremiller_wordpress.wp_posts SET comment_count = (SELECT COUNT(comment_post_id) FROM andremiller_wordpress.wp_comments WHERE andremiller_wordpress.wp_posts.id = andremiller_wordpress.wp_comments.comment_post_id);

In Drupal my urls of the posts where /content/slug_name, and I wanted to keep those the same so any links from outside would stay the same.

To do this I updated the WordPress Permalink settings:

Custom Structure : /content/%postname%

And then made sure the slugname of each post matched the url alias of the article in Drupal.

However, this change made the tags and category urls end up to be /content/tag/<tagname> which I didn’t want. Changing them to the following fixed that up:

Category base: category
Tag base: tag

Now an article can be reached by /content/slug_name, and list of articles with a particle tag by /tag/tag_name.

So far, everything seems to be working just fine.

Enabling telnet on Netgear EVA8000 Digital Entertainer

The Netgear EVA8000 Digital Entertainer has a telnet daemon installed, but by default it is disabled. During bootup the startup script for the telnet daemon examines the contents of /etc/utelnetd.conf and starts the telnet daemon if the contents is set to “ENABLE 1″

Once telnet is enabled you can log into the system with the username “EVA8000″ and the password “Netgear”.

There are two ways to do this depending on which firmware version you are running.

If you’re still using the 1.2.x series of firmware you can use the built-in menu options that allows saving and restoring settings to modify this file.

The steps to accomplish this is documented by flusk on http://mpcclub.com/modules.php?name=Forums&file=viewtopic&t=13503

  1. Create a trial settings backup, using the Supervisor->Advanced Setup->Backup settings option
  2. Confirm that a file was created in the location you’ve set for the EVA to store its library on. The file will be in the backup directory
  3. Create a new file, called utelnetd.conf, in a directory called etc in a temporary location
  4. Change the contents of this file to contain a single line “ENABLE 1″ (without the quotes)
  5. Create a tar archive of this file including the etc directory
  6. Copy the tar file to the EVA Backup directory
  7. On the EVA8000, restore the settings from this file.
  8. Once the EVA has restarted telnet will be enabled and you can log in with username “EVA8000″ password “Netgear”

If, however, you are using one of the later beta firmware versions then the Backup settings option has been removed and you can no longer use this method to enable telnet.

To enable telnet on the newer firmware versions involve editing the firmware image to make the same change as above, changing ENABLE 0 to ENABLE 1 in the utelnetd.conf file.

I posted this same method on the Netgear Beta forums and it has been confirmed to work by others. (http://forum1.netgear.com/showthread.php?t=20991&page=2&p=95783)

  1. Split the FW image into three parts. A 32 byte md5 header, the bootloader+kernel and finally the jffs2 image. If you’re using the same FW as me (V2.1.16IS.IMG):
  2. FW=EVA8000_V2.1.16IS.IMG
    dd if=$FW of=crc bs=1 count=32
    dd if=$FW of=bootkernel bs=1 skip=32 count=$((0x210000))
    dd if=$FW of=jffsroot bs=1 skip=$((0x210020))
  3. Edit the jffs2 image with bvi and change the ‘ENABLE 0′ to ‘ENABLE 1′ inside the inode for dirent utelnetd.conf (Near offset 0x5cfd8 of the jffs2 image).
  4. Re-run jffs2dump -c on the new image. This will complain and say that the block now has an invalid CRC.
  5. Luckily it also prints out what the expected CRC should be.. so, make a note of this and update the crc (77 C7 E9 3E should be changed to 36 F6 F2 27 at offset 0x5CFD0 in the jffs2 image).
  6. Re-run jffs2dump again to make sure its consistent
  7. Combine the extracted bootloader+kernel with the new image and calculate the new md5sum:
  8. cat bootkernel jffsroot_mod > tempimage
    md5sum tempimage
  9. Create a new file with the ASCII portion of the md5sum in it, making sure it is exactly 32 bytes long (no newline)
  10. Stitch everything back together:
  11. cat newcrc bootkernel jffsroot_mod > telnet_enabled.img

Note that some of these steps can be skipped because the CRC of the JFFS2 inode will usually be the same across image versions because the contents doesn’t change. The steps are only provided for completeness. In reality all you would have to do is edit the original image, change ENABLE 0 to ENABLE 1, change the JFFS2 CRC (which will be the same values as above), strip off the first 32 bytes of the new images, re-calculate the md5sum and insert it at the start of the file.

Mounting a hard disk image including partitions using Linux

A while ago I thought it would be a good idea to make a backup of my Linux server by just dumping the complete disk to a file. In retrospect, it would have been much easier had I just dumped the individual filesystems.

When I finally got around to using this backup, long after the 10GB disk had perished I realized that to use the loopback device to mount a filesystem it actually needs a filesystem to mount. What I had was a disk image, including partition table and individual partitions. To further complicate matters the data partition was also not the first partition inside this image.

For reference, I created this image using the Unix ‘dd’ tool:

# dd if=/dev/hda of=hda.img
30544113+0 records in
30544113+0 records out
# ls -lh
-rw-r--r-- 1 root    root  9.6G 2008-01-22 14:12 hda.img

I followed the instructions on http://www.trekweb.com/~jasonb/articles/linux_loopback.html to try and mount the partitions inside the disk image, but ran into two problems.

To mount a partition inside the disk image you need to calculate the offset of where the partition starts. You can use fdisk to show this information to you, but you need to specify the number of cylinders if you are using a disk image.

You then also need to multiply the start and end numbers with the calculated sectors to get a byte offset.

I found another tool more useful for this task, called parted. If you are using Ubuntu, you can install it with ‘apt-get install parted’

# parted hda.img
GNU Parted 1.7.1
Using /data/rabbit/disk_image/test2
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit
Unit?  [compact]? B
(parted) print
Disk /data/rabbit/disk_image/test2: 10262568959B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number  Start        End           Size         Type     File system  Flags
1      32256B       106928639B    106896384B   primary  ext3         boot
2      106928640B   1184440319B   1077511680B  primary  linux-swap
3      1184440320B  10256924159B  9072483840B  primary  ext3
(parted) quit

Now we have the offsets and we can use those to mount the filesystems using the loopback device:

#mount -o loop,ro,offset=32256 hda.img /mnt/rabbit

That mounted the first partition, the ‘boot’ partition, but this didn’t have the data on it that I was looking for. Lets try to mount partition number 3.

#umount /mnt/rabbit
#mount -o loop,ro,offset=1184440320 test2 /mnt/rabbit
#mount: wrong fs type, bad option, bad superblock on /dev/loop0,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail  or so

Oops, that doesn’t look right. According the article referred to above if you are using a util-linux below v2.12b then you cannot specify an offset higher than 32bits. I’m using util-inux 2.13 which shouldn’t have that problem, and besides, my offset is well below the 32bit limit.

The article also offers an alternative loopback implementation that supports mounting partitions within an image, but that requires patching and recompiling your kernel which I would rather not do.

Instead I decided to extra ct the filesystem from the image which would then allow me to mount it without specifying an offset.
Doing this is quite straightforward with ‘dd’. You need to give ‘dd’ a skip count, or, how far into the source to start copying, and a count, how much to copy.
Here you can either use the single byte offsets retrieved with parted or divide them by 512 and let ‘dd’ use 512 byte blocks. Copying just one byte at a time takes a very long time, so I suggest using a larger block size.

Here is the command I used to extract my filesystem. Skip is 2313360 (1184440320/512) and Count is 17719695 (9072483840/4)

#dd if=hda.img of=hda3.img bs=512 skip=2313360 count=17719695
17719695+0 records in
17719695+0 records out
9072483840 bytes (9.1 GB) copied, 485.679 seconds, 18.7 MB/s

After extracting the filesystem I was able to mount it without any problems.

# mount -o loop hda3.img /mnt/rabbit/
# df -h /mnt/rabbit
Filesystem            Size  Used Avail Use% Mounted on
/data/rabbit/image/hda3.img
8.4G  6.3G  1.7G  80% /mnt/rabbit

Recovering reserved space in ext2 and ext3 filesystems

When using the ext2 or ext3 filesystem by default 5% of the available blocks is reserved for use by the root user. This allows the system to continue running if non-root users fill up the file system and also assists in preventing file fragmentation because the filesystem does not fill up completely.

Under certain circumstances this extra protection is not required or desired. For example, I have a 1TB ext3 array specifically to store media on seperate from my operating system and other file systems. The root user will never write to this file system so reserving 5% (50GB) is wasted space.

To recover this space you can use the tune2fs command and specify the -m 0 option. Here is an example.

Before the tune with the default 5% reserve:

root@pooh:/data# df -h /data
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/data_vol_grp-data_vol
921G  867G  7.2G 100% /data

The tune2fs command to adjust the reserved percentage to 0.

root@pooh:/data# tune2fs -m 0 /dev/data_vol_grp/data_vol

The available space after adjusting the reserved space.

root@pooh:/data# df -h /data
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/data_vol_grp-data_vol
921G  867G   54G  95% /data