Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Building my custom initramfs
View unanswered posts
View posts from last 24 hours

Goto page 1, 2  Next  
Reply to topic    Gentoo Forums Forum Index Kernel & Hardware
View previous topic :: View next topic  
Author Message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Thu Feb 04, 2021 11:20 am    Post subject: Building my custom initramfs Reply with quote

I'm planning to write a small script for creation of my custom initramfs.

But what's the best way to pre-test it? In a chroot?
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!


Last edited by Zucca on Sat Feb 06, 2021 4:01 pm; edited 1 time in total
Back to top
View user's profile Send private message
Hu
Moderator
Moderator


Joined: 06 Mar 2007
Posts: 21635

PostPosted: Thu Feb 04, 2021 7:26 pm    Post subject: Reply with quote

What kind of testing do you want? If you have ready access to run a virtual machine, that might give you a more faithful test environment. This may not be appropriate if you need to test how the initramfs handles devices that are difficult to expose to the VM.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Thu Feb 04, 2021 8:05 pm    Post subject: Reply with quote

I'd need to test how the initramfs initscript (linuxrc) does work and if all the dependencies are met.
I understand that the kernel module loading part needs to be done in virtual environment, but all the rest should work in chroot... I think.
But could I load the current running kernel in qemu and pass my newly creted initramfs to it? I've never done so. But I think from technical stand point it should be possible. I'm just not 100% sure.

I use btrfs filesystems on all my setups so I only need btrfs related things in initramfs to mount real root.
My hardware is pretty basic consumer hardware so no exotic parts (except maybe for the InfiniBnad, but that's not needed in initramfs phase anyway).
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Hu
Moderator
Moderator


Joined: 06 Mar 2007
Posts: 21635

PostPosted: Thu Feb 04, 2021 8:36 pm    Post subject: Reply with quote

You probably can pass your current kernel, if it supports an initramfs. Such support is optional, and you may have excluded it.
Back to top
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3137

PostPosted: Thu Feb 04, 2021 11:04 pm    Post subject: Reply with quote

Zucca, the thing that always gave me the most trouble was getting it to actually start init, so that's one thing. You can't really test it in any other way than trying to boot it.

Once I had this done, I came up with a little cheat that let me avoid rebuilding the archive over and over and over and over again: I just put a stub init script in the initramfs, which would download the actual init script from tftp.
At this point I could update the script and just reboot the VM

Quote:
But could I load the current running kernel in qemu and pass my newly creted initramfs to it? I've never done so
qemu supports direct kernel boot option.
This mode does require a disk image it can prepend the kernel and initramfs to, but the content of that disk is irrelevant. I suppose you could even get away with /dev/null.

Make sure you have the necessary hardware drives builtin and not compiled as modules. It's not strictly required, but it does make life much easier.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Fri Feb 05, 2021 11:28 am    Post subject: Reply with quote

After reading some bits and pieces, I came up with this oneliner:
Code:
xargs -ra /etc/portage/sets/initramfs-internal qlist | egrep '/s?bin/' | xargs lddtree --copy-to-tree /usr/src/initramfs/

The portage set @initramfs-internal contains all the packages I think I need inside initramfs.

Then the hardest part of creating the linuxrc/init script...
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3137

PostPosted: Fri Feb 05, 2021 6:21 pm    Post subject: Reply with quote

Busybox can act as the init (pid 1).
If you let it be the master, it will start /etc/init.d/rcS as the "helper" program, so this is where there interesting stuf happens. Mount /proc and /dev and figure the rest out from interactive shell.
Talking of which, busybox init will start a bunch of agettys according to /etc/inittab, which is more convenient than making your script PID 1 and dropping to shell from there.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sat Feb 06, 2021 4:13 pm    Post subject: Reply with quote

Since this topic somewhat derailed I changed its title.

I'm trying now to test extract the cpio archive... I used --no-absolute-filenames when creating the archive to be able to extract the files into a directory rather than to the root of my filesystem.
I get errors that don't make any sense like cpio: libncursesw.so.6.2: Cannot symlink to ‘lib64/libncursesw.so.6’: No such file or directory

If any of you know what causes this, please explain. :P Meanwhile I'll try to rtfm and solve this...

EDIT: If I pass --dereference upon creating the archive I get: cpio: lib64/libblkid.so.1: Cannot open: No such file or directory
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3137

PostPosted: Sat Feb 06, 2021 4:21 pm    Post subject: Reply with quote

I don't think --no-absolute-filenames is necessary. never used it myself, it was just
find . | cpio -o -H newc | gzip > initramfs.gz (or bzip2. Couldn't find the correct params to xz, kernel's builtin decompressor is somewhat limited)
and
gzip -cd initramfs.gz | cpio -i


Are you sure you actually put the libraries into your cpio and not just the symlinks?
Are those messages errors or warnings? Links should be created even if target files didn't exist.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sat Feb 06, 2021 4:29 pm    Post subject: Reply with quote

Yup. While creating --no-absolute-filenames is not needed.
But while extracting --make-directories with --directory solves the problem.

I can now start to perform some test inside chroot. :)
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Tue Feb 09, 2021 8:55 am    Post subject: I can only run busybox providede commands Reply with quote

Well... I'm testing my initramfs now by extracting the archive and chrooting into it.
However commands outside busybox don't work.
What is going on?
Code:
# chroot initramfs busybox sh
/ # ls /bin/
[              date           gunzip         md5sum         pkill          showkey        umount
[[             dd             gzip           mesg           pmap           shred          uname
ar             deallocvt      hd             microcom       printenv       shuf           uncompress
arch           df             head           minips         printf         sleep          unexpand
ash            diff           hexdump        mkdir          ps             softlimit      uniq
awk            dirname        hexedit        mkfifo         pscan          sort           unit
base64         dmesg          hostname       mknod          pstree         split          unix2dos
basename       dnsdomainname  id             mkpasswd       pwd            ssl_client     unlink
bb             dos2unix       install        mktemp         pwdx           stat           unlzma
bbconfig       du             ionice         more           readlink       strings        unlzop
bbsh           dumpkmap       iostat         mount          realpath       stty           unshare
bc             dumpleases     ipcrm          mountpoint     renice         su             unxz
blkdiscard     echo           ipcs           mpstat         reset          sum            unzip
bunzip2        ed             kbd_mode       mt             resize         svc            uptime
busybox        egrep          kill           mv             resume         svok           users
bzcat          eject          killall        nano           rev            sync           usleep
bzip2          env            last           nc             rm             tac            vi
cal            envdir         less           netcat         rmdir          tail           vlock
cat            envuidgid      link           netstat        rnano          tar            volname
chattr         expand         linux32        nice           rx             tee            w
chgrp          expr           linux64        nl             script         telnet         wall
chmod          factor         ln             nmeter         scriptreplay   test           watch
chown          fallocate      login          nohup          sed            tftp           wc
chpst          false          lpq            nproc          seq            time           wget
chrt           fatattr        lpr            nsenter        setarch        timeout        which
chvt           fdflush        ls             nslookup       setfattr       top            who
cksum          fgconsole      lsattr         nuke           setkeycodes    touch          whoami
clear          fgrep          lsof           openvt         setpriv        tr             whois
cmp            find           lspci          passwd         setserial      traceroute     xargs
comm           flock          lsscsi         paste          setsid         traceroute6    xxd
conspy         free           lsusb          patch          setuidgid      true           xz
cp             fsync          lzcat          pgrep          sh             truncate       xzcat
cpio           fuser          lzma           pidof          sha1sum        ts             yes
cryptpw        getopt         lzop           ping           sha256sum      tty            zcat
cttyhack       grep           lzopcat        ping6          sha3sum        ttysize
cut            groups         man            pipe_progress  sha512sum      udhcpc6
/ # /bin/nano
sh: /bin/nano: not found

_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
GDH-gentoo
Veteran
Veteran


Joined: 20 Jul 2019
Posts: 1530
Location: South America

PostPosted: Tue Feb 09, 2021 2:00 pm    Post subject: Re: I can only run busybox providede commands Reply with quote

Zucca wrote:
However commands outside busybox don't work.
What is going on?
Code:
# chroot initramfs busybox sh
...
/ # /bin/nano
sh: /bin/nano: not found

Were they linked to static libraries (including the libc)? If no, are the required shared libraries and dynamic linker present in the initramfs? If you are not sure, use the file command on the initramfs' nano binary outside the chroot.
Back to top
View user's profile Send private message
NeddySeagoon
Administrator
Administrator


Joined: 05 Jul 2003
Posts: 54237
Location: 56N 3W

PostPosted: Tue Feb 09, 2021 2:19 pm    Post subject: Reply with quote

Zucca,

You need all the bts in the right places too.
Code:
$ ldd /bin/bash
   linux-vdso.so.1 (0x00007ffc1c7f7000)
   libreadline.so.8 => /lib64/libreadline.so.8 (0x00007fadcce22000)
   libc.so.6 => /lib64/libc.so.6 (0x00007fadccc61000)
   libtinfow.so.6 => /lib64/libtinfow.so.6 (0x00007fadccc23000)
   /lib64/ld-linux-x86-64.so.2 (0x00007fadccf80000)


The kernel has a script to make the initrd.
Code:
/usr/src/linux usr/gen_init_cpio /root/initrd/initramfs_list > /boot/initramfs_static
where /root/initrd/initramfs_list describes everfthing that is to go into the initramfs.
I've always used files from the live filesystem but that's not such a good idea as things change. I won't do that again as it wakes it impossible to tweak the init script is years to come.

Did you bind mount all the pseudo filesystems into the chroot?
_________________
Regards,

NeddySeagoon

Computer users fall into two groups:-
those that do backups
those that have never had a hard drive fail.
Back to top
View user's profile Send private message
Goverp
Advocate
Advocate


Joined: 07 Mar 2007
Posts: 2008

PostPosted: Tue Feb 09, 2021 3:17 pm    Post subject: Reply with quote

Or you can use my script to generate the initramfs_list
_________________
Greybeard
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Tue Feb 09, 2021 4:30 pm    Post subject: Reply with quote

Thanks guys. :)
While you were commenting I realized that my problem was with symlinks.
Now it works.

I made preliminary script for building my own initramfs.
Code:
#!/usr/bin/bash

packagelist="/etc/portage/sets/initramfs-internal"
extrafilesdir="/etc/initramfs"

cpiocmd="cpio --create"

{
        xargs -ra "$packagelist" qlist | egrep '/s?bin/' | xargs lddtree --list 2> /dev/null | while read f
        do
                while [ -L "$f" ]
                # We have a symlink to handle
                do
                        echo "$f"
                        l="$(readlink "$f")"
                        if [ "${l:0:1}" != "/" ]
                        then
                                # Link target is a relative path.
                                # Get the absolute path so that cpio can store it.
                                f="$(realpath --no-symlinks "$(dirname "$f")/$l")"
                        fi
                done
                echo "$f"
        done | awk '!seen[$1]++' | tee /tmp/initcpio.lst | $cpiocmd

        find "$extrafilesdir" -depth -printf '%P\n' | $cpiocmd --directory "$extrafilesdir"

} | pigz --stdout -9 > /tmp/initramfs.cpio.gz


Now I can customize 'init' script inside the initramfs by editing /etc/initrtamfs/init.

I may add busybox back eventually, but for now this is the quick and dirty way.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Tue Feb 09, 2021 4:39 pm    Post subject: Reply with quote

NeddySeagoon wrote:
The kernel has a script to make the initrd.
Code:
/usr/src/linux usr/gen_init_cpio /root/initrd/initramfs_list > /boot/initramfs_static
where /root/initrd/initramfs_list describes everfthing that is to go into the initramfs.
I've always used files from the live filesystem but that's not such a good idea as things change. I won't do that again as it wakes it impossible to tweak the init script is years to come.

Did you bind mount all the pseudo filesystems into the chroot?
That script seems to be absent on sys-kernel/gentoo-kernel. :\
I tried to search it before.

goverp, your script look really comprehensive, but still gives user many choices. Nice.

GDH-gentoo
, dynamically linked. My script pulls the files from the running system.
Although I thought of running emerge to compile static binaries into the root of initramfs, but since I have them already and it was only a matter of gathering all the libraries... I went that way.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Wed Feb 10, 2021 7:40 am    Post subject: Reply with quote

I almost completely rewrote my script. There was (an obvious) problem with including files from s?bin -directories when the file isn't a binary recognized by ldd (a shell script).

I managed to keep the code fairly small, which is my target.
My second targets are to make it "dumb" (more UNIX like). It will have three goals:
  • read a list of files from the current running system, process each file using ldd and then add the required libraries to the list too
  • copy each file as-is into cpio archive
  • do the same for "extra files" (this includes module and firmare files)


This way one could leave the first list completely empty, but have all the required files in the extra files directory. I'm thinking emerging the required packages and using the "extra files" directory as root directory. I'll look into that maybe when I'm finished with this.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Goverp
Advocate
Advocate


Joined: 07 Mar 2007
Posts: 2008

PostPosted: Sun Mar 14, 2021 4:02 pm    Post subject: Reply with quote

If anyone's interested, I've updated my script to generate the initramfs_list.
It's a bit cleaner, some bugs in path handling are fixed, the output is in a more sensible order, and you can now tell it to include /etc/fstab and mountpoints for selected filesystem types (e.g. "ext4,vfat"), which is useful if you want to be able to "mount -a" or just issue "mount <mountpoint>" in an init script. Since in my world the initramfs is built at kernel make time, it automatically gets an up-to-date fstab.
_________________
Greybeard
Back to top
View user's profile Send private message
Buffoon
Veteran
Veteran


Joined: 17 Jun 2015
Posts: 1369
Location: EU or US

PostPosted: Sun Mar 14, 2021 4:05 pm    Post subject: Reply with quote

Don't forget Tetris, guys.
_________________
Life is a tragedy for those who feel and a comedy for those who think.
Back to top
View user's profile Send private message
halcon
l33t
l33t


Joined: 15 Dec 2019
Posts: 629

PostPosted: Fri Mar 26, 2021 8:02 pm    Post subject: Reply with quote

Goverp wrote:
If anyone's interested, I've updated my script to generate the initramfs_list.

Thank you for that script. It is useful and beatiful :)

I have a question:

Code:
      case "$library" in
      *=\>*)
         # ...
      */*)
         # ...
      linux-*)
         # ...


And I see, for example, such output:
Code:
ldd /usr/sbin/haveged 2>/dev/null
        linux-vdso.so.1 (0x00007ffcc6e58000)
        libhavege.so.2 => /usr/lib64/libhavege.so.2 (0x00007fd1a8e31000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fd1a8c71000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd1a8e74000)


As far as I understand, for the second case, there can be only [[:space:]] before /. Which bash pattern is corresponding to that rule? Something like [[:space:]]+/* ...

EDIT

Also... My script version has a separate ldd call before the loop, so:
Code:
      __ldd_result="$(ldd "${__binary}" 2>/dev/null)" || true
      while read -r __line ; do
         case "${__line}" in
         *=\>*)
            __linker_dep="${__line#*=> }"
            __linker_dep="${__linker_dep% (*}"
            # ...
            ;;
         */*)
            __linker_dep="${__line% (*}"
            # ...
            ;;
         *linux-*)
            # Kernel-provided - nothing needed
            ;;
         *)
            exit_err_1 "Unknown line pattern in __ldd_result (${__line})"
            ;;
         esac
      done < <( echo "${__ldd_result}" )

^^ And I had to add * before linux-*, otherwise lines like that with linux-vdso.so.1 were caught as an error (Unknown line pattern)

EDIT

Finally, I've chosen this:
Code:
      __ldd_result="$(ldd "${__binary}" 2>/dev/null)" || true
      while read -r __line ; do
         __clean="$(echo ${__line} | sed -r 's/^[[:space:]]*//')"
         if [[ "${__clean}" =~ =\> ]]; then
            __linker_dep="${__clean#*=> }"
            __linker_dep="${__linker_dep% (*}"
            # ...
         elif [[ "${__clean}" =~ ^/ ]]; then
            __linker_dep="${__clean% (*}"
            # ...
         elif [[ ! "${__clean}" =~ ^linux- ]]; then
            exit_err_1 "Unknown line pattern in __ldd_result (${__clean})"
         fi
      done < <( echo "${__ldd_result}" )

_________________
A wife asks her husband, a programmer:
- Could you please go shopping for me and buy one carton of milk, and if they have eggs, get 6?
He comes back with 6 cartons of milk.
- Why did you buy 6 cartons of milk?
- They had eggs.
Back to top
View user's profile Send private message
Goverp
Advocate
Advocate


Joined: 07 Mar 2007
Posts: 2008

PostPosted: Sat Mar 27, 2021 10:18 am    Post subject: Reply with quote

halcon wrote:
...
As far as I understand, for the second case, there can be only [[:space:]] before /. Which bash pattern is corresponding to that rule? Something like [[:space:]]+/* ...

I was coding for dash, in which case the possibilities for patterns in the case statement (and elsewhere), are much restricted. A character class such as [0-9] matches only one character; there are no regex things like [0-9]+, that merely matches [0-9][+] in regex terms. And there's no [:space:] category, you'd have to write [ \t] (except \t isn't allowed there) and so forth.
So the one that matches is the rather too powerful */*).

Dash coding is AFAIK effectively upwards-compatible with Bash
_________________
Greybeard
Back to top
View user's profile Send private message
halcon
l33t
l33t


Joined: 15 Dec 2019
Posts: 629

PostPosted: Sat Mar 27, 2021 2:03 pm    Post subject: Reply with quote

Goverp wrote:
I was coding for dash, in which case the possibilities for patterns in the case statement (and elsewhere), are much restricted. A character class such as [0-9] matches only one character; there are no regex things like [0-9]+, that merely matches [0-9][+] in regex terms.

I've found that there is nearly the same picture in bash - case statement doesn't support regexes, but only globbing. This is why I've chosen to use if statements.
_________________
A wife asks her husband, a programmer:
- Could you please go shopping for me and buy one carton of milk, and if they have eggs, get 6?
He comes back with 6 cartons of milk.
- Why did you buy 6 cartons of milk?
- They had eggs.
Back to top
View user's profile Send private message
Goverp
Advocate
Advocate


Joined: 07 Mar 2007
Posts: 2008

PostPosted: Sun Mar 28, 2021 11:20 am    Post subject: Reply with quote

Perhaps it should be looking for "*.so.[0-9]* ". I'll give it a try.

EDIT no, my code, at least, should parse the library stuff a bit smarter:
Code:
# Changed to parse the ldd lines at read time rather than messy parse later
                ldd "$path" 2>/dev/null | while read -r soname arrow file _
                do
                        library="${soname%%.so.*}"
                        if      [ "$library" = "linux-vdso" ]
                        then    continue        # Nothing to do, it's part of the kernel
                        elif    [ "$arrow" = "=>" ] && [ -f "$file" ]
                        then    listFile "$file"
                        elif    [ -f "$soname" ]
                        then    listFile "$soname"
                        else    error "Unexpected ldd $path output $soname $arrow $file"
                        fi
                done


I'll put the changes into my version in the wiki (and while I'm there, remove the ill-considered /etc/fstab thing)
_________________
Greybeard
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sun Mar 28, 2021 3:53 pm    Post subject: Reply with quote

I've managed to create quite small busybox -based initramfs image, which is just a single cpio file (instead of many).
Now I'd need to create some sort of function for resuming from hibernate. You guys have any samples to show?

Something strange is still happening with dynamic binaries... When trying to run one I only get sh: <binary name> not found -type of messages. All the libraries are there so I don't quite know what's going on. I need to continue tests inside a chroot.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
NeddySeagoon
Administrator
Administrator


Joined: 05 Jul 2003
Posts: 54237
Location: 56N 3W

PostPosted: Sun Mar 28, 2021 3:57 pm    Post subject: Reply with quote

Zucca,

The binaries are not in the right path?
The linker can't find them?
The permissions are not correct. I think only x matters as there is only a root user in the initrd.
_________________
Regards,

NeddySeagoon

Computer users fall into two groups:-
those that do backups
those that have never had a hard drive fail.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Kernel & Hardware All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum