TinyGentoo
| Please format this article according to the Style Guidelines and Wikification suggestions, then remove this notice {{Wikify}} from the article.
Reason(s):
|
Contents |
[edit] Summary
[edit] Goal
This article will show how to build a very minimal Gentoo installation, considerably smaller than 64MB. To reach this goal, 'busybox' and 'uClibc' will be used. The finished installation will be bootable, and can be put for example on small portable media such as an USB-stick or SD-card.
[edit] Why this Wiki was created
I've got a 64MB USB flash disk, and I wanted Gentoo on it, but to still have plenty of room for other files. Because there wasn't anything already out there, I figured it out for myself, and this is pretty much a HOWTO make a Tiny Gentoo (under 5MB) using uClibc and busybox (what the embedded guys use). Links to other (larger) projects and pages that were very helpful for me are at the #References section.
[edit] Process overview
The steps to reach the goal are:
- Download files
- Setup chroot for building environment
- Chroot to building environment
- Build building environment
- Create the final environment, /tinygentoo is assumed in this document
- Package the final environment into an initramfs image
- Create partitions, copy files and install bootloader (GRUB)
[edit] Requirements
- USB flash disk or flash card (min. 8MB)
- About 500MB free on your HDD (depends on how you decide to go on about things)
- A motherboard/laptop that supports booting from a USB flash disk
- Root privileges (chroot as unprivileged user will not work)
- Some free time
[edit] Build environment
[edit] Download stage-files
Choose a Gentoo mirror close to you , then hop into experimental/x86/embedded/stages, if your arch is x86. Download the Stage3 file, as an alternative you may choose Stage 1 or 2 if you want to play around more than what is necessary.
You can choose different file and folder names than in this document, I'm just using ones that will explain what they are for. Basically we're just following the Gentoo Handbook Chapter 5, but with a few differences, most of the stuff we don't need to do because we'll only be chrooting into it.
You can consult a more detailed guide for creating the chroot if you want.
[edit] Entering the chroot
The build environment will be put in /mnt/gentoo_uclibc.
cd /mnt/gentoo_uclibc tar xjpf <path to>/stage* cp -L /etc/resolv.conf etc/resolv.conf mkdir -p usr/portage
And what you'll need to repeat every time when entering the chroot:
mount --bind /dev /mnt/gentoo_uclibc/dev mount -t proc proc /mnt/gentoo_uclibc/proc chroot /mnt/gentoo_uclibc/ /bin/bash env-update && source /etc/profile
tar xjf <path to>/portage-<timestamp>.tar.bz2 -C /mnt/gentoo_uclibc/usr
[edit] Basic setup
We do want all the symlinks for busybox, and ccache, and only minimal versions of packages that support that use flag.
# To use previously built packages, use the -k option with emerge
FEATURES="ccache buildpkg"
USE="minimal"
# Store .tbz2's in their own directory
PKGDIR="${PORTDIR}/packages/uclibc"
The uclibc stages on the mirrors are quite old, so you will need to change the profile to a newer version. Emerge ccache first so that portage can use it for all the other packages. Then update all the packages, emerge the 2.6 kernel sources and copy the default bash login scripts to root's home directory.
# ln -snf /usr/portage/profiles/uclibc/x86 /etc/make.profile # emerge ccache # emerge -au portage # emerge -auDN world # emerge vanilla-sources # cp /etc/skel/.bash_profile /etc/skel/.bashrc /root/ # mkdir /tinygentoo
If you get sandbox violation errors when upgrading coreutils just do
FEATURES="-sandbox" emerge coreutils
If you get errors while running the ancient emerge against the new portage tree use the following work-around:
On your parent Gentoo system create a package containing a working portage:
# quickpkg --include-config=y portage
You now have a package file at '/usr/portage/packages/All/portage-#.#.#.#.tbz2'. Chroot back into the subsystem as explained above and type 'cd /' to go to the root. Now extract the working portage over the embedded system chroot by typing:
# tar xvjf /usr/portage/packages/All/portage-#.#.#.#.tbz2
Finally you should emerge portage itself using the new emerge (from the parent system) to make sure everything is fine: 'emerge portage'
If sys-apps/gawk fails, see bug 195368. Copy /usr/include/netdb.h to /usr/include/netdb.h.orig. Then add the following after line 403 in netdb.h:
# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ # define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */ # define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose returned address type. */
After a successful emerge world you may want to emerge app-portage/gentoolkit and run revdep-rebuild. If this fails because it wants to emerge an old python that is no longer supported(?), try emerge -pv python to find out which version you have, and then unemerge all old versions by using emerge -C '<python-X.Y.Z'. Replace X.Y.Z by the version you have, and don't forget the single quotes to prevent misinterpretation of the '<' sign by the shell. After this, do rm /root/.revdep* and try the revdep-rebuild again.
If the emerge -auDN world fails on busybox, then first emerge uclibc, then retry emerging world.
If after the above sys-apps/busybox fails with error: '__NR_clock_gettime' undeclared you need to upgrade sys-libs/uclibc. For the current version (1.8.2 as well as 1.7.4) uclibc-0.9.29 is needed, which is not in portage. See bug 182094 for updated ebuilds.
Alternatively, to work around the busybox problem, you can do the following
FEATURES="keepwork" emerge busybox # this will fail with the __NR_clock_gettime error cd /var/tmp/portage/sys-apps/busybox-1.x.y/work/busybox-1.x.y make menuconfig Deselect "BusyBox Settings"->"BusyBox Library Tuning"->"Use Clock Gettime" Exit configuration mkdir -p /etc/portage/savedconfig/sys-apps/busybox cp .config /etc/portage/savedconfig/sys-apps/busybox cd $HOME USE="savedconfig" emerge busybox
[edit] Final environment
An initramfs will be booted after the kernel. This initramfs will hold the full environment. Everything that will finally be turned into this initramfs will be in /tinygentoo/. Using ROOT=/tinygentoo before emerge commands will emerge the packages into that directory. This way you do not need portage or gcc in there, but only the packages you really want will end up in the final environment.
[edit] Basic setup of /tinygentoo
[edit] Emerge the base packages
Emerge lines that do not have ROOT=/tinygentoo will be installed into the chroot so that it will be able to compile the other packages without errors. We do not add symlink to /etc/make.conf because that would interfere with later updating the baselayout-2, which will need to be unmasked first. See emerge --help if you're not sure what the options used do. Please note that at the time of writing, baselayout 2.0.0 is the most recent version. You can choose to unmask newer versions (and their dependencies) when needed.
mkdir -p /etc/portage echo "=sys-apps/baselayout-2.0.0 **" >> /etc/portage/package.keywords echo "=sys-apps/openrc-0.2.1-r1 **" >> /etc/portage/package.keywords echo "=sys-fs/udev-118-r2 **" >> /etc/portage/package.keywords echo "=sys-apps/baselayout-2.0.0" >> /etc/portage/package.unmask echo "=sys-apps/openrc-0.2.1-r1" >> /etc/portage/package.unmask ROOT=/tinygentoo USE=make-symlinks emerge -avkN =sys-apps/baselayout-2.0.0 uclibc busybox
[edit] Setting up users
chroot into /tinygentoo/ and change the root password.
Please note, the shell shipped with busybox is /bin/ash, not /bin/bash:
chroot /tinygentoo /bin/ash passwd
Add a regular user. Change foo to your username:
addgroup -g 100 users adduser -h /home/foo -s /bin/ash -G users foo
exit the /tinygentoo chroot:
exit
[edit] Set the hostname
Replace TinyGentoo if you would like to use some other hostname. /etc/hostname is read by /sbin/init, see /tinygentoo/etc/inittab. echo "TinyGentoo" > /tinygentoo/etc/hostname.
For more help see Busybox Init Documentation
[edit] Writing fstab
The root filesystem will be mounted as ramfs by the kernel. The only downside to this is that unlike tmpfs it does not have a size limit, so writing a lot to / could fill up your ram. Anything that is on tmpfs uses nearly no ram when empty and grows when needed but wont use up all of the ram, leaving room for applications to run.
Feel free to be creative, just remember that flash doesnt like being written to lots and lots (incorrect, see notes), so do not mount / or /var onto it. sda1 is the partiton on the USB stick that will contain the bootloader files, the kernel and the initrd. /dev/sda2 will be the partition that you see when in windows, and you can use it to store any settings/files from TinyGentoo too.
none /tmp tmpfs defaults 0 0 none /proc proc defaults 0 0 /dev/sda1 /boot ext2 noauto,ro 0 0 /dev/sda2 /mnt/dongle vfat defaults 0 0
Make the two directories that do not yet exist mkdir /tinygentoo/boot /tinygentoo/mnt/dongle
[edit] Writing /init
This step is optional. Instead of having this file you could add init=/sbin/init to the grub kernel line.
/init is the file that the kernel executes right after loading the content of the initramfs. If you are using initrd instead of initramfs, rename this file to linuxrc
#!/bin/ash echo echo echo " Welcome to TinyGentoo." echo echo echo " * Setting umask.." umask 022 echo " * Mounting /proc.." mount -t proc none /proc # NOTE FROM ANOTHER USER # I also have this in here to successfully populate /dev by using mdev echo " * Mounting metafilesystems..." mount -t proc proc /proc mount -t tmpfs mdev /dev && mkdir /dev/pts mount -t devpts devpts /dev/pts mount -t sysfs sysfs /sys echo " * Populating /dev..." echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s # END OF NOTE echo " * Starting init.." exec <dev/console >dev/console 2>&1 exec chroot . /sbin/init echo " *** Starting init failed! ***" echo " * Trying to start a shell.." exec /bin/ash
Remember to make it executable chmod +x /tinygentoo/init
If you would like to be able to use the same script with both initrd or initramfs, you can symlink one /init to /linuxrc.
cd /tinygentoo ln -s init linuxrc
Optional, but if you would like to change the timezone, edit /tinygentoo/etc/TZ. For example, echo UTC > /tinygentoo/etc/TZ.
[edit] Emerging the wanted packages into /tinygentoo
Choose what packages you want. app-portage/esearch foo in your regular Gentoo to easily find out what the packages are. The examples will provide you with an installation that can browse the web (lynx), connect to IRC (scrollz), run and connect to SSH servers (dropbear) and screen, that I don't know how some people live without.
ROOT=/tinygentoo emerge -avk lynx scrollz dropbear screen
That's it for /tinygentoo. chroot back in if you want to get a feel for it.
You have to set this before you try to emerge coreutils:
export gl_cv_func_getcwd_path_max=yes
[edit] Kernel
In theory you could just use a kernel built outside the uClibc chroot, but that would get confusing.
[edit] Kernel configuration
Not very hard really, and because we will be using an initramfs image most things can be compiled as modules if you wish to do so. Disable everything that you don't want or need to keep the size of the kernel image down.
cd /usr/src/linux make menuconfig
make menuconfig SUBARCH=i386
| Linux Kernel Configuration: Linux Kernel Configuration: vanilla-sources-2.6.16 for TinyGentoo |
Code maturity level options ---> [*] Prompt for development and/or incomplete code/drivers General setup ---> [*] Enable 16-bit UID system calls [*] Optimize for size [*] Configure standard kernel features (for small systems) ---> Note: if you are using uClibc 0.9.28 or older, you need to enable 16bit UID interfaces in the Linux kernel. This has been fixed in svn so newer uclibc's will use the 32 bit interfaces. You don't want HIGHMEM if you haven't 1G or more RAM. Processor type and features ---> (4GB) High Memory Support [*] MTRR (Memory Type Range Register) support [ ] Symmetric multi-processing support Enable this if you want normal hard disk support Device Drivers ---> ATA/IDE/MFM/RLL support ---> < > ATA/IDE/MFM/RLL support What we need for reading from the USB stick to work: SCSI support ---> <*> SCSI support <*> SCSI disk support Of course we need the following because we run with an initrd root filesystem: Block devices ---> <*> RAM disk support (16) Default number of RAM disks (4096) Default RAM disk size (kbytes) [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support For networking remember to select the driver for the chipset of your NIC. Use lspci to find out what you've got. I have on-board nForce2 and some cheap PCI card with an RTL-8139 chip. Network device support --->
< > Dummy net driver support
Ethernet (10 or 100Mbit) --->
[*] Ethernet (10 or 100Mbit)
[*] EISA, VLB, PCI and on board controllers
<m> nForce Ethernet support (EXPERIMENTAL)
<m> RealTek RTL-8139 PCI Fast Ethernet Adapter support
Keyboard support might be nice: Input device support ---> [*] Keyboards 'Cos we'd like to be able to actually do something (enabled and hidden by default if CONFIG_EMBEDDED is not set): Character devices ---> [*] Virtual terminal [*] Support for console on virtual terminal [*] Unix98 PTY support We don't want X stuff: < > /dev/agpgart (AGP Support) < > Direct Rendering Manager Use lspci -v |
As a final touch, you may also need something else than the default us keymap for your future system. If you need it, you can build the proper keymap for your keyboard layout inside the kernel issuing the following command from within the /usr/src/linux directory:
loadkeys -m <path_to_keymap> > drivers/char/defkeymap.c
An example for french layout:
loadkeys -m /usr/share/keymaps/i386/azerty/fr.map.gz > drivers/char/defkeymap.c
[edit] Compiling the kernel
Now just:
make -j2 && make modules_install cp arch/i386/boot/bzImage /tmp/vmlinuz-tinygentoo
If you go back to menuconfig and change things, clean out the old modules so there wont be any extra ones taking up space:
rm -r /lib/modules/* make modules_install
or if you don't want do the next step (coping modules) you can launch this command:
make INSTALL_MOD_PATH=/tinygentoo modules_install
[edit] Copying the modules
We want all the modules inside the initrd, so they'll need to be copied there.
mkdir -p /tinygentoo/lib/modules cp -vr /lib/modules/* /tinygentoo/lib/modules/
[edit] Packaging /tinygentoo
We want everything under /tinygentoo to be turned into a single initramfs image. Don't forget to copy the kernel modules to /tinygentoo before this step!
[edit] Cleaning up
Copy the files to some other place so you can easily restart if you mess up, then remove all the files you don't need or want.
cp -r /tinygentoo /tmp/ rm -r /tmp/tinygentoo/var/*/* /tmp/tinygentoo/tmp/*
If you want to see how much space its using:
du -hs /tmp/tinygentoo
[edit] Creating the initramfs image
To create the initramfs image we will use cpio to create an archive of the files that the kernel can understand, and gzip it to make it smaller.
cd /tmp/tinygentoo && find . | cpio -H newc -o | gzip -9 > /tmp/initramfs-tinygentoo.igz
[edit] Preparing the USB flash disk
Basically we just want one partiton for the TinyGentoo boot files, and one partiton for saving files that you want to keep even after a reboot, and that will also be accessable from Windows.
[edit] Backing up the old data
Just in case you don't like it or just want to try it or.... something else, back up what you have got on your dongle (USB flash disk) right now. Make sure that you use the correct device, it might not be /dev/sda if you have other drives showing up as SCSI. Those could be a SATA hdd, a camera or an MP3 player. fdisk -l will show you what partitions are seen by linux.
Preferably do all the partitioning stuff outside the uClibc chroot, but you could do it from in there too if you've fallen in love with it :P
We'll just raw copy the whole disk. Note: sda is the whole disk, sda1 is only the first partition, it does not include the MBR/partiton table. Gzip it too to save space. 4K blocks to read to make it slightly faster, but its still slow..
cd /root dd if=/dev/sda of=dongle_backup.img bs=4K gzip dongle_backup.img
[edit] Creating the partitions
Clear the partition table and use fdisk (or something else if you don't like fdisk) to create the partitions.
dd if=/dev/zero of=/dev/sda bs=1 count=512 fdisk /dev/sda
Change the size of the boot partition so that it will fit your kernel + initrd.img + 1-2MB, though you could make it larger if you would like to use it for other stuff too.
Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1024, default 1): <enter> Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-1024, default 1024): +6M
To make it bootable:
Command (m for help): a Partition number (1-4): 1
Then the vfat partition. Your cylinder numbers propably will not match mine, don't worry bout that.
Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 2 First cylinder (95-1024, default 95): <enter> Last cylinder or +size or +sizeM or +sizeK (95-1024, default 1024): <enter> Using default value 1024
Change the type to FAT32 so that Windows will see it correctly
Command (m for help): t Partition number (1-4): 2 Hex code (type L to list codes): b Changed system type of partition 2 to b (W95 FAT32)
Then to check everything is OK
Command (m for help): p
If yes, write and exit
Command (m for help): w
[edit] Formatting the partitions
There isn't really any good reason to use something other than ext2 for the boot partition. You may need to emerge dosfstools for vfat formatting support. The -F 32 makes it FAT32 to support longer filenames and stuff. Change label to what name you would like the partition to have.
mke2fs /dev/sda1 mkfs.vfat -v -F 32 -n <i>label</i> /dev/sda2
[edit] Installing GRUB
If you do not yet have grub, mount /boot && emerge grub.
First you will need to copy the stages. e2fs_stage1_5 is optional, and you may delete it after grub has embedded it. Make sure you have /boot mounted to be able to copy the files from there.
mkdir /mnt/dongle mount /dev/sda1 /mnt/dongle mkdir /mnt/dongle/grub cp /boot/grub/stage? /boot/grub/e2fs_stage1_5 /mnt/dongle/grub/ umount /mnt/dongle grub grub> device (hd0) /dev/sda grub> root (hd0,0) grub> setup (hd0) grub> quit mount /dev/sda1 /mnt/dongle rm /mnt/dongle/grub/e2fs_stage1_5
[edit] Alternative GRUB configuration
In my case, I had to do use the following commands.
mkdir /mnt/dongle mount /dev/sda1 /mnt/dongle mkdir /mnt/dongle/grub cp /boot/grub/stage? /boot/grub/e2fs_stage1_5 /mnt/dongle/grub/ touch /mnt/dongle/grub/usb_flag umount /mnt/dongle grub grub> find /grub/usb_flag (hd1,0) grub> root (hd1,0) grub> setup (hd1) grub> setup (hd1,0) grub> quit mount /dev/sda1 /mnt/dongle rm /mnt/dongle/grub/usb_flag
The difference being that I had to setup BOTH the MBR and the boot partition's MBR. Until I did this, my BIOS would not boot from the USB stick.
[edit]
GRUB looks for menu.lst, not grub.conf, but you may make a symlink to grub.conf from menu.lst and then edit grub.conf.
Add init=/sbin/init to the kernel line if you do not have a linuxrc file.
timeout 3 title TinyGentoo kernel /vmlinuz-tinygentoo vga=791 initrd /initramfs-tinygentoo.igz
Set vga=ask to get a prompt to be able to select the resolution for your console. With the ramdisk_size= option you can set how large you would like your / to be, in KB. Don't set it too high if because you will also need RAM for applications to run, but you've got to set it large enough for the uncompressed initrd.img and dynamic files that will be created.
[edit] Copying the important files
Something you need to do to get it working..
cp /tmp/vmlinuz-tinygentoo /tmp/initramfs-tinygentoo.igz /mnt/dongle/ umount /mnt/dongle
[edit] BIOS Setup, Reboot and Enjoy!
Reboot, hit Del, F2 or whatever it is that you need to do to enter the BIOS configuration. Find the section where you can change the boot order, and select USB-HDD, USB-ZIP or something similar to have the highest priority. Save and exit, and reboot with the USB stick attached.
[edit] Where to go from here?
If all goes well, you'll be in your shiny new TinyGentoo, that you will still need to learn to use though.. You will propably want to write a script to get the net going and maybe something to save your settings.
[edit] TODO
- udev and hotplug
- xorg + wm and stuff
- Getting sectors and cylinders right on the disk
- Scripts and hopefully an ebuild to make life easier
- Boot floppy to get boot the actual TinyGentoo for those whose BIOS's don't support booting directly from USB (see http://mirror.slitaz.org/floppies/builder/ or http://mirror.slitaz.org/boot/floppy-grub4dos)
- Syslinux instead of GRUB
[edit] Notes
- Computer's working memory is RAM, not Flash. Flash memory has a finite number of erase-write cycle whereas RAM has not.
[edit] References
- man initrd - If you're interested in how initrd works
- 256mb minumum USB flash disk, 256Mb, but it does look very sweet, and its Gentoo based Gentoo.
- Gentoo Network APpliance Easy, extremely effective, modular framework for building small, embedded systems (~15MB+).
- Damn Small Linux 50mb and has X and more apps too.
- HOWTO Small Footprint Gentoo on USB - Great for those who don't want to go with uClibc/have a large flashdisk
- Embedded Gentoo - What all this is based on and wouldn't work without, thank you devs :)
- Similar project , but aimed at [i]embedded[/i] instead of desktop
- uClibc HOWTO Same as in this wiki, just done slightly differently
- Set the timezone in uClibc based installs
- HOWTO get your USB flash cylinders/tracks/sectors set up so the BIOS won't choke on it
- Official Gentoo LiveUSB HOWTO, using the minimal-livecd.iso
- Small (32 MB) livecd based on this on uclibc and gentoo
- Gentoo Cross Development Guide
- Initramfs An interesting page about initramfs in general, and Genkernel's initramfs in particular
- Install HOWTO for floppy, CD and USB
- uClibc bootstrap project