# Unpacking Genkernel or gentoo.igz initramfs | Strange result

## travisx

I am trying to unpack the 2005.1 initramfs (gentoo.igz) so that I can tweak it for use on a LiveUSB, but I am not having much success.

Strangely, when I attempt to use cpio to unpack the gentoo.igz initramfs file (or any file made by Genkernel, actually), I get a directory structure with a handful of files (like fstab), but it is missing obviously necessary files such as linuxrc and init.  The total quantity of files unpacked is less than 4k, while the gzipped gentoo.igz file is 17M.

I've really been banging my head against the wall on this.  I assume that I must be doing something wrong, because the initramfs works correctly in operation.

Scouring the internet and the Gentoo forums has proved only that others have the same unanswered question.

Because everything is more clear in code:

```
# gunzip -c gentoo.igz | cpio -H newc -t

.

etc

etc/fstab

bin

sys

var

var/lock

var/lock/dmraid

usr

usr/bin

usr/sbin

dev

dev/null

dev/tty1

dev/console

temp

proc

sbin

5 blocks

```

I've tried this on two very different and up to date Gentoo systems, but I get the same result.

This is going to seriously frustrate me until someone lets me in on the (probably trivial) thing that I'm doing wrong.

Thanks,

-- Travis

----------

## irondog

Genkernels initramfs is a file consisting of several gzipped cpio archives concatenated to each other. It's not so easy to extract it. 

It tried to do it in C. This is the result. It's quite unpolished, but just works for me.

```
#include <sys/types.h>

#include <unistd.h>

#include <sys/stat.h>

#include <fcntl.h>

static unsigned char magick[]="070701000000000000000000000000000000000000000100000000000000000000000000000000000000000000000

00000000b00000000TRAILER!!!";

static int src, dest;

int c[100];

int rec_read(int matches, int x) {

        int n_read;

        n_read = read(src, &c[x], 1);

        if(n_read != 1)

                return -1;

        if(c[x] == magick[matches]) {

                if ( matches != strlen(magick) - 1) {

                        rec_read(matches + 1, x + 1);

                } else {

                        printf("MAGIC FOUND\n");

                        do {

                                n_read = read(src, &c, 1);

                        } while( n_read == 1 && c[0] != '0');

                        lseek(src, -1, SEEK_CUR);

                        rec_read(0, 0);

                }

        } else {

                write(dest, &c[x - matches] , 1);

                lseek(src, 0 - matches, SEEK_CUR);

                return 0;

        }

}

int main () {

        int c, n_read;

        src = open("in", O_RDONLY);

        dest = open("out", O_RDWR | O_CREAT, 0666);

        while (rec_read(0, 0) != -1);

        lseek(dest, -1, SEEK_CUR);

        write(dest, &magick, strlen(magick));

//        write(dest, "\0\0\0\0\0", 5);

        close(src);

        close(dest);

}

       

```

Use it like this:

```

$ zcat /boot/initramfs.gz > ./in

$ ./split-iniramfs

$ cpio -i -H newc < out
```

----------

## capira

Thanks for the answer irondog!

I just wonder if anybody knows how to pack initramfs again ...I have to add a delay in linuxrc in order to give time to the udev module to create the /dev/sda* entry.

Is the linuxrc script placed in anywhere in the kernel dir or genkernel dir so I had just to add that line once and let genkernel do the rest?

Thanks in advance.

PS. All this is because I want boot gentoo from a external USB hard disk

----------

## capira

The way of repacking the files into a initramfs file is explained here.

----------

## jong357

Sorry to be ignorant here but could someone clarify further on how to do this. I'm having the same issue. That looks like a C file to me that you would want to compile into a binary called split-initramfs.... I'm not having much luck with it.

```

$ gcc -o split-iniramfs split-iniramfs.c

split-iniramfs.c:7: error: missing terminating " character

split-iniramfs.c:8:1: invalid suffix "b00000000TRAILER" on integer constant

split-iniramfs.c:8: error: parse error before '!' token

split-iniramfs.c:8: error: missing terminating " character

split-iniramfs.c: In function `rec_read':

split-iniramfs.c:15: error: `src' undeclared (first use in this function)

split-iniramfs.c:15: error: (Each undeclared identifier is reported only once

split-iniramfs.c:15: error: for each function it appears in.)

split-iniramfs.c:35: error: `dest' undeclared (first use in this function)

split-iniramfs.c: In function `main':

split-iniramfs.c:42: error: `src' undeclared (first use in this function)

split-iniramfs.c:43: error: `dest' undeclared (first use in this function)
```

Thanks for any and all help.... I've been "banging" my head on this one for a while as well and this post is the only thing I can find on the web concerning how to handle this type of initrd.

----------

## jong357

I got it... When I copied the above C code from irondog's post, the very long line at the top somehow got a space inserted in there somewhere.

syntax highlighting gave it away after I stared at it long enough... This damn initramfs image really burned me out. Haven't tried messing with it yet but atleast the binary compiled....   :Wink: 

----------

## piavlo

i get an error cpio: premature end of file then extracting the cpio archive repacked by the split-initramfs code

both in x86 amd amd64 2005.1 livecd gentoo.igz files.

----------

## capira

Well, I have the same problem here but I everything seems to work fine.

----------

## wmd

For what ever reason your C didn't work for me. So I wrote this sloppy code.

mv gentoo.igz gentoo-image.gz

gunzip gentoo-image.gz

usage: ./unigz.pl gentoo-image

```

#!/usr/bin/perl -w

#

use strict;

use File::Slurp qw(slurp);

my $ifile = slurp($ARGV[0], binmode=> ':raw');

my $newfile;

my $i=1;

my @newfiles = split(/TRAILER!!!/,$ifile);

`mkdir $ARGV[0].dir`;

foreach $newfile (@newfiles)

{

        open F, "> ./$ARGV[0].dir/$i";

        print F $newfile;

        print F "TRAILER!!!\0";

        close F;

        `cd $ARGV[0].dir; cpio -i -H newc < $i; rm $i; cd ..`;

        $i++;

}

```

I got a few errors, but no file was missing besides the devices. (such as dev/console)

----------

## beep

hi,

i tried with the new 2006.0 image and found out that the magick has been change to

```

07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!

```

cheers,

::beep

----------

## druggo

 *wmd wrote:*   

> For what ever reason your C didn't work for me. So I wrote this sloppy code.
> 
> mv gentoo.igz gentoo-image.gz
> 
> gunzip gentoo-image.gz
> ...

 

great !

----------

## Offpist2000

To many error when compiling the C-code. I used the following

with good result:

Start in an empty directory, replace the TRAILER after each cpio archive

with some nonsense, and unpack everuthing

zcat /tmp/usb-live/gentoo.igz | sed -e 's/TRAILER/notTRAILER/g' | cpio -idv

Just ignore the cpio errors.

Do the modifications and the put it pack together:

 find * | cpio --quiet --dereference -o -H newc | gzip -9 > /tmp/usb-live/gentoo.igz

/Offpist2000

----------

## tap3w0rm

here is a fix to the problems everyone was having. This also included the magic that allows the use on 2006.0 and 2006.1 files

i added a few includes and put in the correct magic. This shoudl compile for everyone.

```

#include <sys/types.h>

#include <unistd.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

#include <stdio.h>

static unsigned char magick[]="07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!";

static int src, dest;

int c[100];

int rec_read(int matches, int x) {

        int n_read;

        n_read = read(src, &c[x], 1);

        if(n_read != 1)

                return -1;

        if(c[x] == magick[matches]) {

                if ( matches != strlen(magick) - 1) {

                        rec_read(matches + 1, x + 1);

                } else {

                        printf("MAGIC FOUND\n");

                        do {

                                n_read = read(src, &c, 1);

                        } while( n_read == 1 && c[0] != '0');

                        lseek(src, -1, SEEK_CUR);

                        rec_read(0, 0);

                }

        } else {

                write(dest, &c[x - matches] , 1);

                lseek(src, 0 - matches, SEEK_CUR);

                return 0;

        }

}

int main () {

        int c, n_read;

        src = open("in", O_RDONLY);

        dest = open("out", O_RDWR | O_CREAT, 0666);

        while (rec_read(0, 0) != -1);

        lseek(dest, -1, SEEK_CUR);

        write(dest, &magick, strlen(magick));

//        write(dest, "\0\0\0\0\0", 5);

        close(src);

        close(dest);

}

```

----------

## cerise8192

I actually couldn't get either version of the C or perl to work, so I hacked up the perl.

Gunzip the .igz and run it as the only argument to this script and voila!

```

#!/usr/bin/perl -w

#

use strict;

use File::Slurp qw(slurp);

my $ifile = slurp($ARGV[0], binmode=> ':raw');

my $newfile;

my $i=1;

my @newfiles = split(/TRAILER!!!/,$ifile);

`mkdir $ARGV[0].dir`;

foreach $newfile (@newfiles)

{

        $newfile =~ s/^[\0]*//;

        if($newfile){

           open F, "> ./$ARGV[0].dir/$i";

           $newfile = $newfile . "TRAILER!!!";

           for(my $null=22*16+21;$null>0;$null--){

              $newfile = $newfile . "\0";

           }

           print F $newfile;

           close F;

           print "$i\n";

           `cd $ARGV[0].dir; cpio -i -H newc < $i; rm $i; cd ..`;

           $i++;

        }

}

```

----------

