CSCI 373 System Administration — Finding a file I

Getting an image

Type the command mount to verify the location of the /boot file system.

Variant one — On your Pi

The /boot file system of a Raspberry Pi is formatted as a FAT16 file system. It’s a small file system so we’re just going to make a copy of it. This is the only time, we’ll need to use the sudo command.

Either use the dd command to copy the first Megabyte of the disk image of your root file system. Take a look at a recent copy of the dd manual page because there has been some changes to how byte size is specified.

…$ sudo dd if=/dev/mmcblk0p1 of=/tmp/boot.img bs=1M

We’ve stored the image of /boot into the file boot.img The file boot.img should be about the same size as the /boot file system. Use df to verify this.

Change the ownership of /tmp/boot.img so you won’t have to sudo any longer. Also, make it read-only, so you won’t accidently overwrite it.

Variant two — Using a image stored on the CSCI server

There is an image already stored with the web page. If you want to use it, then use the following command to create a soft link to the image. Of course, you really ought to dd.

…$ ln -s /home/brock/sysadmin/notes/boot.img .

The reference

Download a copy of the Microsoft EFI FAT32 File System Specification. It is the only reference we will use.

The specification is in MS Word format. You will have to accept a license agreement.

The BPB and its fields

Read pages 7 and 8 which talks about the BPB (BIOS Parameter Block), which is contained in the first 512 bytes of the file system image. Use the dd command to copy those first 512 bytes into a file called boot.BPB.img.

…$ dd if=boot.img of=boot.BPB.img bs=512 count=1

Take a look at the contents of the BPB, but first open the manual page for od, a program with some enthusiastic fans.

…$ od boot.BPB.img
…$ od -c boot.BPB.img
…$ od -t a -N 100 -t d2 boot.BPB.img

The BPB contains many fields that specify the layout of the file system. We are going to get copies of the ones we will need in our task. We will use od to get these fields and assign them to shell variables. We are using the variable name of the Microsoft specification.

This is going to be tedious.

Bytes per sector

Sectors are the smallest unit of disk allocation. The size of the sector is stored in two bytes starting at the eleventh byte of the BPB.

…$ od -A d -j 11 -N 2 -t d2 boot.BPB.img 
0000011    512
0000013
…$ BPB_BytsPerSec=512

I am using the variable names of the Microsoft document. It might be a lot easier just to start up an interactive session of Python to do the arithmetic. Otherwise, be prepared to type a lot of $, (, and \.

Sectors per cluster

However, files are allocated in clusters. Sectors are just too small for efficient file allocation. You’ll find the numbers of sector per cluster at offset 13. It’s stored in a single byte.

…$ od -A d -j 13 -N 1 -t d1 boot.BPB.img 
0000013   16
0000014
…$ BPB_SecPerClus=16

Number of reserved sectors

This is the number of sectors reserved for BPB and, presumably, other stuff. The Microsoft specification states that it should “never be anything other than 1” for a FAT16 file system. (However, I have seen other numbers...)

…$ od -A d -j 14 -N 2 -t d2 boot.BPB.img 
0000014     1
0000016
…$ BPB_RsvdSecCnt=1

Number of FATs

The FAT file system is named after the File Allocation Table, a big table that forms the pointers to the clusters used for files and directories. How many FATs are there? There ought to be two.

…$ od -A d -j 16 -N 1 -t d1 boot.BPB.img 
0000016    2
0000017
…$ BPB_NumFATs=2

Root directory entry count

This is a count of the number of root directory entries for FAT12 and FAT16 file systems. Each of these entries is 32-bytes long. Expect to find 512 entries which works out to about 200 files.

…$ od -A d -j 17 -N 2 -t d2 boot.BPB.img 
0000017    512
0000019
…$ BPB_RootEntCnt=512

Total sectors

This one is a little tricky because the number of sectors may by larger than the maximum number (65535 or 216-1) that can be stored in 16 bits. If the 16-bit field stored at offset 19 is 0, you must look at the 32-bit field stored at offset 32.

At this point, your numbers may differ from those you see below. This is because the size of the boot partition varies between different Raspberry Pi relases.

…$ od -A d -j 19 -N 2 -t d2 boot.BPB.img 
0000019      0
0000021
…$ BPB_TotSec16=0
…$ od -A d -j 32 -N 4 -t d4 boot.BPB.img 
0000032      114688
0000036
…$ BPB_TotSec32=114688
…$ TotSec=$BPB_TotSec32
…$ echo $TotSec
114688

Sanity check

If you multipy the number of sectors by the number of bytes per sectors, you will find out the size of the file system. The ought to be the same size as the file system image. It certainly can’t be bigger.

…$ echo $(( $TotSec * $BPB_BytsPerSec ))
58720256
…$ ls -lL boot.img
-rw-r--r-- 1 root root 58720256 Mar 24 09:17 boot.img

If you get a syntax error, you probably used the wrong variable name for either TotSec or BPB_BytsPerSec.

Isn’t arithmetic a bash in this shell! In any case, that one looks good.

What kind of FAT

We’ve made it to pages 13 & 14 of the specification where we can take our first look at the File Allocation Table or FAT.

However, we better first figure out where the data sectors really are located. That requires knowing the sizes of the root directory (for FAT16) and FAT structures.

Number of root directory sectors

In a FAT12 or FAT16 file system, a fixed number of sectors are allocated for the root directory. You’ll have to do some arithmetic to figure out how many. But just follow the Microsoft documentation.

…$ RootDirSectors=$(( ( ( $BPB_RootEntCnt * 32 ) + ( $BPB_BytsPerSec - 1 ) ) / $BPB_BytsPerSec ))
…$ echo $RootDirSectors
32

If you perform this calculation for a FAT32 system, it will always assign 0 because BPB_RootEnCnt is 0.

Number of FAT sectors

We have to read some more BPB fields to determine the number of sectors used to store a single copy of the FAT.

…$ od -A d -j 22 -N 2 -t d2 boot.BPB.img 
0000022     32
0000024
…$ BPB_FATSz16=32
…$ FATSz=$BPB_FATSz16

First data cluster

The first data cluster follows the reserved sectors, the FAT sectors and the root directory sectors (for FAT16). Determine the first data sector and the number of data sectors.

…$ FirstDataSector=$(( $BPB_RsvdSecCnt + ( $BPB_NumFATs * $FATSz ) + $RootDirSectors ))
…$ echo $FirstDataSector
112
…$ DataSec=$(( $TotSec - ( $BPB_RsvdSecCnt + ( $BPB_NumFATs * $FATSz ) + $RootDirSectors ) ))
…$ echo $DataSec
114576

In my opinion, this doesn’t seem correct if BPB_RsvdSecCnt is 1, because the then you wouldn’t be starting on a cluster boundary. However, I’ll hold my judgment for a little while.

What FAT

The officially MS-sanctioned way to determine FAT type (FAT12, FAT16, or FAT32) is to calculate the number of sectors and compare that number to 212, 216 and 232.

…$ CountofClusters=$(( $DataSec / $BPB_SecPerClus ))
…$ echo $CountofClusters
7161

This is officially a FAT16 file system because 212 is 4096 and 216 is 65536,

Root directory

Finally, let’s copy the root directory into the file boot.rootdir.img. Note that we are copying from the original disk image.

…$ rootDirStart=$(( $BPB_RsvdSecCnt + $BPB_NumFATs * $FATSz ))
…$ echo $rootDirStart
80
…$ echo $RootDirSectors
32
…$ dd if=boot.img of=boot.rootdir.img bs=512 count=$RootDirSectors skip=$rootDirStart

This is going to be weird because most files in this directory do have long names. On page 24 of the Microsoft document, you will find the directory entry structure, but on page 26 you find the long directory entry structure. (Here are some examples on long names:

Type the following command to look at the directory entires. The first should contain the spread out filename boot. You should find a directory entry every 32 bytes, but remember that most of them are long entries.

…$ od -A d -t a boot.rootdir.img | more