diff --git a/src/experimental/glibc-busybox/.config b/src/experimental/glibc-busybox/.config new file mode 100644 index 000000000..1b2a837e9 --- /dev/null +++ b/src/experimental/glibc-busybox/.config @@ -0,0 +1,18 @@ +# You can find the latest Linux kernel source bundles here: +# +# http://kernel.org +# +KERNEL_SOURCE_URL=https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.4.6.tar.xz + +# You can find the latest GNU libc source bundles here: +# +# http://gnu.org/software/libc +# +GLIBC_SOURCE_URL=http://ftp.gnu.org/gnu/glibc/glibc-2.23.tar.bz2 + +# You can find the latest BusyBox source bundles here: +# +# http://busybox.net +# +BUSYBOX_SOURCE_URL=http://busybox.net/downloads/busybox-1.24.2.tar.bz2 + diff --git a/src/experimental/glibc-busybox/00_prepare.sh b/src/experimental/glibc-busybox/00_prepare.sh new file mode 100755 index 000000000..b1f8e4ed3 --- /dev/null +++ b/src/experimental/glibc-busybox/00_prepare.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +rm -rf work +mkdir work + +# -p stops errors if the directory already exists +mkdir -p source + diff --git a/src/experimental/glibc-busybox/01_get_kernel.sh b/src/experimental/glibc-busybox/01_get_kernel.sh new file mode 100755 index 000000000..0d79b79a1 --- /dev/null +++ b/src/experimental/glibc-busybox/01_get_kernel.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Grab everything after the '=' character +DOWNLOAD_URL=$(grep -i KERNEL_SOURCE_URL .config | cut -f2 -d'=') + +# Grab everything after the last '/' character +ARCHIVE_FILE=${DOWNLOAD_URL##*/} + +cd source + +# Downloading kernel file +# -c option allows the download to resume +wget -c $DOWNLOAD_URL + +# Delete folder with previously extracted kernel +rm -rf ../work/kernel +mkdir ../work/kernel + +# Extract kernel to folder 'work/kernel' +# Full path will be something like 'work/kernel/linux-3.16.1' +tar -xvf $ARCHIVE_FILE -C ../work/kernel + +cd .. + diff --git a/src/experimental/glibc-busybox/02_build_kernel.sh b/src/experimental/glibc-busybox/02_build_kernel.sh new file mode 100755 index 000000000..c5543e5fc --- /dev/null +++ b/src/experimental/glibc-busybox/02_build_kernel.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +cd work/kernel + +# Change to the first directory ls finds, e.g. 'linux-3.18.6' +cd $(ls -d *) + +# Cleans up the kernel sources, including configuration files +make mrproper + +# Create a default configuration file for the kernel +make defconfig + +# Changes the name of the system +sed -i "s/.*CONFIG_DEFAULT_HOSTNAME.*/CONFIG_DEFAULT_HOSTNAME=\"minimal\"/" .config + +# Compile the kernel with optimization for "parallel jobs" = "number of processors" +# Good explanation of the different kernels +# http://unix.stackexchange.com/questions/5518/what-is-the-difference-between-the-following-kernel-makefile-terms-vmlinux-vmlinux +make bzImage -j $(grep ^processor /proc/cpuinfo | wc -l) + +# Install kernel headers in "./usr" (this is not "/usr") which are used later. +make headers_install + +cd ../../.. + diff --git a/src/experimental/glibc-busybox/03_get_glibc.sh b/src/experimental/glibc-busybox/03_get_glibc.sh new file mode 100755 index 000000000..a68d3edcb --- /dev/null +++ b/src/experimental/glibc-busybox/03_get_glibc.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Grab everything after the '=' character +DOWNLOAD_URL=$(grep -i GLIBC_SOURCE_URL .config | cut -f2 -d'=') + +# Grab everything after the last '/' character +ARCHIVE_FILE=${DOWNLOAD_URL##*/} + +cd source + +# Downloading musl file +# -c option allows the download to resume +wget -c $DOWNLOAD_URL + +# Delete folder with previously extracted glibc +rm -rf ../work/glibc +mkdir ../work/glibc + +# Extract glibc to folder 'work/glibc' +# Full path will be something like 'work/glibc/glibc-1.1.11' +tar -xvf $ARCHIVE_FILE -C ../work/glibc + +cd .. + diff --git a/src/experimental/glibc-busybox/04_build_glibc.sh b/src/experimental/glibc-busybox/04_build_glibc.sh new file mode 100755 index 000000000..008caad52 --- /dev/null +++ b/src/experimental/glibc-busybox/04_build_glibc.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +cd work/kernel +cd $(ls -d *) +WORK_KERNEL_DIR=$(pwd) +cd ../../.. + +cd work/glibc + +# Change to the first directory ls finds, e.g. 'glibc-2.22' +cd $(ls -d *) + +rm -rf ./glibc_objects +mkdir glibc_objects + +rm -rf ./glibc_installed +mkdir glibc_installed +cd glibc_installed +GLIBC_INSTALLED=$(pwd) + +cd ../glibc_objects +../configure --prefix= --with-headers=$WORK_KERNEL_DIR/usr/include --disable-werror +#../configure --prefix=$GLIBC_INSTALLED --with-headers=$WORK_KERNEL_DIR/usr/include --enable-static-ns --disable-werror +#../configure --prefix=$GLIBC_INSTALLED --with-headers=$WORK_KERNEL_DIR/usr/include --disable-werror + +make -j $(grep ^processor /proc/cpuinfo | wc -l) + +#set DESTDIR=$GLIBC_INSTALLED +#export DESTDIR +make install DESTDIR=$GLIBC_INSTALLED -j $(grep ^processor /proc/cpuinfo | wc -l) + +#unset DESTDIR + +cd ../../.. + diff --git a/src/experimental/glibc-busybox/05_prepare_glibc.sh b/src/experimental/glibc-busybox/05_prepare_glibc.sh new file mode 100755 index 000000000..dd01e774a --- /dev/null +++ b/src/experimental/glibc-busybox/05_prepare_glibc.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +cd work/kernel +cd $(ls -d *) +WORK_KERNEL_DIR=$(pwd) +cd ../../.. + +cd work/glibc + +# Change to the first directory ls finds, e.g. 'glibc-2.22' +cd $(ls -d *) + +cd glibc_installed + +mkdir -p usr +cd usr + +unlink include 2>/dev/null +ln -s ../include include + +unlink lib 2>/dev/null +ln -s ../lib lib + +cd ../include + +unlink linux 2>/dev/null +ln -s $WORK_KERNEL_DIR/usr/include/linux linux + +unlink asm 2>/dev/null +ln -s $WORK_KERNEL_DIR/usr/include/asm asm + +unlink asm-generic 2>/dev/null +ln -s $WORK_KERNEL_DIR/usr/include/asm-generic asm-generic + +unlink mtd 2>/dev/null +ln -s $WORK_KERNEL_DIR/usr/include/mtd mtd + +cd ../../../.. + +exit 0 + +unlink musl-ar 2>/dev/null +ln -s `which ar` musl-ar + +unlink musl-strip 2>/dev/null +ln -s `which strip` musl-strip + +unlink linux 2>/dev/null +ln -s /usr/include/linux linux + +unlink mtd 2>/dev/null +ln -s /usr/include/mtd mtd + +if [ -d /usr/include/asm ] +then + unlink asm 2>/dev/null + ln -s /usr/include/asm asm +else + unlink asm 2>/dev/null + ln -s /usr/include/asm-generic asm +fi + +unlink asm-generic 2>/dev/null +ln -s /usr/include/asm-generic asm-generic diff --git a/src/experimental/glibc-busybox/06_get_busybox.sh b/src/experimental/glibc-busybox/06_get_busybox.sh new file mode 100755 index 000000000..672bb5841 --- /dev/null +++ b/src/experimental/glibc-busybox/06_get_busybox.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Grab everything after the '=' character +DOWNLOAD_URL=$(grep -i BUSYBOX_SOURCE_URL .config | cut -f2 -d'=') + +# Grab everything after the last '/' character +ARCHIVE_FILE=${DOWNLOAD_URL##*/} + +cd source + +# Downloading busybox source +# -c option allows the download to resume +wget -c $DOWNLOAD_URL + +# Delete folder with previously extracted busybox +rm -rf ../work/busybox +mkdir ../work/busybox + +# Extract busybox to folder 'busybox' +# Full path will be something like 'work/busybox/busybox-1.23.1' +tar -xvf $ARCHIVE_FILE -C ../work/busybox + +cd .. + diff --git a/src/experimental/glibc-busybox/07_build_busybox.sh b/src/experimental/glibc-busybox/07_build_busybox.sh new file mode 100755 index 000000000..ff7373300 --- /dev/null +++ b/src/experimental/glibc-busybox/07_build_busybox.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +cd work/glibc +cd $(ls -d *) +cd glibc_installed +GLIBC_INSTALLED=$(pwd) + +cd ../../../.. + +cd work/busybox + +# Change to the first directory ls finds, e.g. 'busybox-1.23.1' +cd $(ls -d *) + +#PATH_BACKUP=$PATH +#PATH=$GLIBC_INSTALLED:$PATH + +# Remove previously generated artifacts +make distclean + +# Create a default configuration file +make defconfig + +# Change the configuration, so that busybox is statically compiled +# You could do this manually with 'make menuconfig' +# +# Uncomment for static build. +# +#sed -i "s/.*CONFIG_STATIC.*/CONFIG_STATIC=y/" .config + +GLIBC_INSTALLED_ESCAPED=$(echo \"$GLIBC_INSTALLED\" | sed 's/\//\\\//g') + +#echo $GLIBC_INSTALLED_ESCAPED +#exit 0 + +# Uncomment after some tests +# +sed -i "s/.*CONFIG_SYSROOT.*/CONFIG_SYSROOT=$GLIBC_INSTALLED_ESCAPED/" .config + +#exit 0 + +#sed -i "s/.*CONFIG_CROSS_COMPILER_PREFIX.*/CONFIG_CROSS_COMPILER_PREFIX=\"uclibc-\"/" .config +#sed -i "s/.*CONFIG_IFPLUGD.*/CONFIG_IFPLUGD=n/" .config +sed -i "s/.*CONFIG_INETD.*/CONFIG_INETD=n/" .config +#sed -i "s/.*CONFIG_FEATURE_WTMP.*/CONFIG_FEATURE_WTMP=n/" .config + +# Compile busybox with optimization for "parallel jobs" = "number of processors" +make busybox -j $(grep ^processor /proc/cpuinfo | wc -l) + +# Create the symlinks for busybox +# It uses the file 'busybox.links' for this +make install + +#PATH=$PATH_BACKUP + +cd ../../.. + diff --git a/src/experimental/glibc-busybox/08_generate_rootfs.sh b/src/experimental/glibc-busybox/08_generate_rootfs.sh new file mode 100755 index 000000000..08cb9b07b --- /dev/null +++ b/src/experimental/glibc-busybox/08_generate_rootfs.sh @@ -0,0 +1,156 @@ +#!/bin/sh + +cd work/glibc +cd $(ls -d *) +cd glibc_installed +GLIBC_INSTALLED=$(pwd) + +cd ../../../.. + +cd work + +rm -rf rootfs + +cd busybox +cd $(ls -d *) + +# Copy all BusyBox generated stuff to the location of our "initramfs" folder. +cp -R _install ../../rootfs +cd ../../rootfs + +# Remove "linuxrc" which is used when we boot in "RAM disk" mode. +rm -f linuxrc + +# Create root FS folders +mkdir dev +mkdir etc +mkdir proc +mkdir root +mkdir src +mkdir sys +mkdir tmp + +# "1" means that only the owner of a file/directory (or root) can remove it. +chmod 1777 tmp + +cd etc + +# The script "/etc/bootscript.sh" is automatically executed as part of the +# "init" proess. We suppress most kernel messages, mount all crytical file +# systems, loop through all available network devices and we configure them +# through DHCP. +cat > bootscript.sh << EOF +#!/bin/sh + +dmesg -n 1 +mount -t devtmpfs none /dev +mount -t proc none /proc +mount -t sysfs none /sys + +for DEVICE in /sys/class/net/* ; do + ip link set \${DEVICE##*/} up + [ \${DEVICE##*/} != lo ] && udhcpc -b -i \${DEVICE##*/} -s /etc/rc.dhcp +done + +EOF + +chmod +x bootscript.sh + +# The script "/etc/rc.dhcp" is automatically invoked for each network device. +cat > rc.dhcp << EOF +#!/bin/sh + +ip addr add \$ip/\$mask dev \$interface + +if [ "\$router" ]; then + ip route add default via \$router dev \$interface +fi + +EOF + +chmod +x rc.dhcp + +# DNS resolving is done by using Google's public DNS servers +cat > resolv.conf << EOF +nameserver 8.8.8.8 +nameserver 8.8.4.4 + +EOF + +# The file "/etc/welcome.txt" is displayed on every boot of the system in each +# available terminal. +cat > welcome.txt << EOF + + ##################################### + # # + # Welcome to "Minimal Linux Live" # + # # + ##################################### + +EOF + +# The file "/etc/inittab" contains the configuration which defines how the +# system will be initialized. Check the following URL for more details: +# http://git.busybox.net/busybox/tree/examples/inittab +cat > inittab << EOF +::sysinit:/etc/bootscript.sh +::restart:/sbin/init +::ctrlaltdel:/sbin/reboot +::once:cat /etc/welcome.txt +::respawn:/bin/cttyhack /bin/sh +tty2::once:cat /etc/welcome.txt +tty2::respawn:/bin/sh +tty3::once:cat /etc/welcome.txt +tty3::respawn:/bin/sh +tty4::once:cat /etc/welcome.txt +tty4::respawn:/bin/sh + +EOF + +cat > nsswitch.conf << EOF +passwd: db files nis +shadow: files +group: db files nis + +hosts: files nisplus nis dns +networks: nisplus [NOTFOUND=return] files + +ethers: nisplus [NOTFOUND=return] db files +protocols: nisplus [NOTFOUND=return] db files +rpc: nisplus [NOTFOUND=return] db files +services: nisplus [NOTFOUND=return] db files + +EOF + +cd .. + +# The "/init" script passes the execution to "/sbin/init" which in turn looks +# for the configuration file "/etc/inittab". +cat > init << EOF +#!/bin/sh +echo "1111111111111111" +echo "1111111111111111" +echo "1111111111111111" +PATH=/lib:$PATH +export PATH +exec /sbin/init + +EOF + +chmod +x init + +# Copy all source files to "/src". Note that the scripts won't work there. +cp ../../*.sh src +cp ../../.config src +cp ../../*.txt src +chmod +rx src/*.sh +chmod +r src/.config +chmod +r src/*.txt + +#cd bin +#cp -r $GLIBC_INSTALLED/lib/* . +#cd .. +cp -r $GLIBC_INSTALLED/* . + +cd ../.. + diff --git a/src/experimental/glibc-busybox/09_pack_rootfs.sh b/src/experimental/glibc-busybox/09_pack_rootfs.sh new file mode 100755 index 000000000..678d9d2e4 --- /dev/null +++ b/src/experimental/glibc-busybox/09_pack_rootfs.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +cd work + +# Remove the old initramfs archive if it exists. +rm -f rootfs.cpio.gz + +cd rootfs + +# Packs the current folder structure in "cpio.gz" archive. +find . | cpio -R root:root -H newc -o | gzip > ../rootfs.cpio.gz + +cd ../.. + diff --git a/src/experimental/glibc-busybox/10_generate_iso.sh b/src/experimental/glibc-busybox/10_generate_iso.sh new file mode 100755 index 000000000..f4a39b763 --- /dev/null +++ b/src/experimental/glibc-busybox/10_generate_iso.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +cd work/kernel +cd $(ls -d *) +WORK_KERNEL_DIR=$(pwd) +cd ../../.. + +rm -f minimal_linux_live.iso +rm -rf work/isoimage + +# This is the root folder of the ISO image +mkdir work/isoimage +cd work/isoimage + +# Search and copy the files 'isolinux.bin' and 'ldlinux.c32' +for i in lib lib64 share end ; do + if [ -f /usr/$i/syslinux/isolinux.bin ]; then + cp /usr/$i/syslinux/isolinux.bin . + if [ -f /usr/$i/syslinux/ldlinux.c32 ]; then + cp /usr/$i/syslinux/ldlinux.c32 . + fi; + break; + fi; + if [ $i = end ]; then exit 1; fi; +done + +# Now we copy the kernel +cp $WORK_KERNEL_DIR/arch/x86/boot/bzImage ./kernel.bz + +# Now we copy the root file system +cp ../rootfs.cpio.gz ./rootfs.gz + +# Copy all source files to "/src". Note that the scripts won't work there. +mkdir src +cp ../../*.sh src +cp ../../.config src +cp ../../*.txt src +chmod +rx src/*.sh +chmod +r src/.config +chmod +r src/*.txt + +# Create ISOLINUX configuration file +echo 'default kernel.bz initrd=rootfs.gz' > ./isolinux.cfg + +# Now we generate the ISO image file +genisoimage -J -r -o ../minimal_linux_live.iso -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table ./ + +# This allows the ISO image to be bootable if it is burned on USB flash drive +isohybrid ../minimal_linux_live.iso 2>/dev/null || true + +# Copy the ISO image to the root project folder +cp ../minimal_linux_live.iso ../../ + +cd ../.. + diff --git a/src/experimental/glibc-busybox/build_minimal_linux_live.sh b/src/experimental/glibc-busybox/build_minimal_linux_live.sh new file mode 100755 index 000000000..fbfd5892c --- /dev/null +++ b/src/experimental/glibc-busybox/build_minimal_linux_live.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +sh 00_prepare.sh +sh 01_get_kernel.sh +sh 02_build_kernel.sh +sh 03_get_musl.sh +sh 04_build_musl.sh +sh 05_prepare_musl.sh +sh 06_get_busybox.sh +sh 07_build_busybox.sh +sh 08_generate_rootfs.sh +sh 09_pack_rootfs.sh +sh 10_generate_iso.sh + diff --git a/src/experimental/glibc-busybox/qemu32.sh b/src/experimental/glibc-busybox/qemu32.sh new file mode 100755 index 000000000..6beeb5dd4 --- /dev/null +++ b/src/experimental/glibc-busybox/qemu32.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +qemu-system-i386 -m 256M -cdrom minimal_linux_live.iso + diff --git a/src/experimental/glibc-busybox/qemu64.sh b/src/experimental/glibc-busybox/qemu64.sh new file mode 100755 index 000000000..8e5174a01 --- /dev/null +++ b/src/experimental/glibc-busybox/qemu64.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +qemu-system-x86_64 -cdrom minimal_linux_live.iso + diff --git a/src/experimental/glibc-busybox/the_dao_of_minimal_linux_live.txt b/src/experimental/glibc-busybox/the_dao_of_minimal_linux_live.txt new file mode 100644 index 000000000..f7771bebc --- /dev/null +++ b/src/experimental/glibc-busybox/the_dao_of_minimal_linux_live.txt @@ -0,0 +1,722 @@ + + The Dao of Minimal Linux Live (15-Feb-2015) + + Author: Ivan Davidov + Website: http://minimal.linux-bg.org + Email: davidov (dot) i {at} gmail [dot] com + + Redistributed by: + + ### ### ### + + Contents + + 1. Preface + 2. Boot Process + 3. Inside The Shell Scripts + 4. Possible Improvements + 5. Next Steps + 6. Epilogue + + ### ### ### + + 1. Preface + + Please feel free to redistribute this document in any form you see fit. I only ask you to + respect my efforts and keep me as the original author. That's all I ask. + + Note that the explanations regarding the script details are based on the "28-Jul-2014" + version of "Minimal Linux Live". Future versions of the scripts may already include some + of the stuff discussed in the section "Possible Improvements". + + ### ### ### + + 2. Boot Process + + The overall boot process is quite complex but we need to know these details since we are + talking about operating systems and to be more precise - Linux based operating systems. + + You can find some general information here: + + http://en.wikipedia.org/wiki/Linux_startup_process + + When we talk about live Linux OS, the overall boot process is the following: + + 1) BIOS gives the execution control to the boot loader present on the boot media such + as CD, DVD, USB flash or something else. + 2) In most cases the boot loader is based on Syslinux. On our boot media we should have + two special files - the kernel file and the initramfs file. + 3) The boot media also contains a special configuration file which points to the location + of the kernel/initramfs files. + 4) Now that Syslinux knows where the kernel file is, it loads it in the RAM and passes + the execution control to it. + 5) The kernel detects the available hardware, loads necessary drivers and then it passes + the execution control to the initramfs. + 6) The initramfs file is an archive which is unpacked automatically by the kernel in the + RAM. The actual execution control is passed to the shell script file /init which must + be present in the initramfs file. + 7) Since we are talking about minimal live CD, in theory /init is not supposed to do much. + All we need form /init is to prepare the environment and provide the user with shell. + In most live Linux distributions the /init script is supposed to do much more work + but in our case for now it is enough to know that the point at which we take the control + is exactly the /init script. + + ### ### ### + + 3. Inside The Shell Scripts + + So far we learned that we need several pieces in order to build a live Linux OS: + + 1) boot loader - to make our media bootable. + 2) kernel file - to take care of the initial system bootstrap process. + 3) initramfs file - to prepare the necessary environment for the user. + + This document focuses on parts (2) and (3). The reason we won't discuss (1) in details is + because the build process that we are going to rely on later, takes care of the boot loader + part automatically. + + The ZIP which you have downloaded contains the following files: + + .config + 0_prepare.sh + 1_get_kernel.sh + 2_build_kernel.sh + 3_get_busybox.sh + 4_build_busybox.sh + 5_generate_rootfs.sh + 6_pack_rootfs.sh + 7_generate_iso.sh + build_minimal_linux_live.sh + + If you have followed the explanation posted on http://minimal.linux-bg.org then you already + know that you need to execute the script "build_minimal_linux_live.sh". If you open this + file with text editor you will find out that all this script does is to execute all other + scripts one by one. + + From this point onwards, I encourage you to execute the script files one by one. We will + start with "0_prepare.sh". If you take a look at the script's contents, you will find out that + all the script does is to create an empty folder named "work". We will store our temporary + work files there. + + OK, let's continue with the kernel. Somehow we need to end up with fully functional kernel which + is able to do the system initialization for us. We need to download the kernel sources, compile + these sources and finally pack the kernel. + + The script "1_get_kernel.sh" downloads the kernel sources and unpacks them. Here is the full + source code of the script: + + #/bin/sh + + DOWNLOAD_URL=$(grep -i KERNEL_SOURCE_URL .config | cut -f2 -d'=') + ARCHIVE_FILE=${DOWNLOAD_URL##*/} + + cd work + rm -f $ARCHIVE_FILE + wget $DOWNLOAD_URL + rm -rf kernel + mkdir kernel + tar -xvf $ARCHIVE_FILE -C kernel + cd .. + + First we read the ".config" file to find the URL for the kernel sources. The URL is stored in + the variable "DOWNLOAD_URL". Then we get the actual name of the archive file and we store the + name in the variable "ARCHIVE_FILE". + + The important part of the script is the line where we get the kernel sources: + + wget $DOWNLOAD_URL + + The next important part of the script is the line where we unpack the kernel sources: + + tar -xvf $ARCHIVE_FILE -C kernel + + At this point we have downloaded and unpacked the kernel sources. So far so good. Now we need + to compile them. We move to the next script in the chain called "2_build_kernel.sh". Here is + the full source code that we are going to analyse: + + #/bin/sh + + cd work/kernel + cd $(ls -d *) + make clean + make defconfig + sed -i "s/.*CONFIG_DEFAULT_HOSTNAME.*/CONFIG_DEFAULT_HOSTNAME=\"minimal-linux-live\"/" .config + make vmlinux + cd ../../.. + + First we navigate to the kernel source folder. Then we execute the following commands: + + make clean + + The above command cleans the output from our previous kernel builds. Obviously, if this is the + first time we go through the build process, we have nothing to clean. + + make defconfig + + The above command creates new ".config" file in the current folder which contains all default + configuration parameters that we need in order to build our new kernel. Note that the defaults + will be either 32 or 64 bit specific, depending on your Linux environment. + + sed -i "s/.*CONFIG_DEFAULT_HOSTNAME.*/CONFIG_DEFAULT_HOSTNAME=\"minimal-linux-live\"/" .config + + The above command searches for a specific line in the ".config" file which contains the string + "CONFIG_DEFAULT_HOSTNAME" and replaces the whole line with the following text: + + CONFIG_DEFAULT_HOSTNAME="minimal-linux-live" + + Later, when you boot up your live Linux OS you can execute the command "uname -a" and you will + see the string "minimal-linux-live" in the output. All we did was to replace the default value + "(none)" with our custom value. + + Now you have a sample command which you can use to search for specific configurations in the + file ".config" and replace these configurations with your own. Obviously, you can skip this + replacement and everything will work just fine. Like I said, the only difference will be that + the default host name will be "minimal-linux-live" instead of "(none)". + + Now we come to the most important and also the slowest part in the whole process. We need to + actually create the kernel. + + make vmlinux + + The above command will compile the Linux kernel. This takes a lot of time, so I guess it's + high time for a short break. The final kernel file is located here: + + arch/x86/boot/bzImage + + OK, at this point we should have a kernel file compiled with default options, where we have + changed the default host name with some other value of our own. Now we move to the next + part. + + The kernel itself is far from enough - we also need some kind of environment with basic + command line tools like ls, cat, mkdir, etc. This environment is called "initramfs" which + stands for "initial RAM file system". This is what we are going to do: + + 1) We are going to download & compile BusyBox. This will give us the basic command line + tools that we need for normal work in console mode. + 2) We will use BusyBox to provide us with some default directory/file structure which + we will modify into our own initramfs file. + + One by one - we need to download and unpack the BusyBox sources. Let's take a look at the + script file "3_get_busybox.sh": + + #/bin/sh + + DOWNLOAD_URL=$(grep -i BUSYBOX_SOURCE_URL .config | cut -f2 -d'=') + ARCHIVE_FILE=${DOWNLOAD_URL##*/} + + cd work + rm -f $ARCHIVE_FILE + wget $DOWNLOAD_URL + rm -rf busybox + mkdir busybox + tar -xvf $ARCHIVE_FILE -C busybox + cd .. + + The contents is almost identical to the one in "1_get_kernel.sh" which we have already + explained above. Long story short - we get the source archive with "wget" and then we + unpack the sources with "tar". That's it. Nothing complex at all. + + Now that we have BusyBox sources we need to compile them. Let's take a look at the next + script "4_build_busybox.sh" which we need to execute: + + #/bin/sh + + cd work/busybox + cd $(ls -d *) + make clean + make defconfig + sed -i "s/.*CONFIG_STATIC.*/CONFIG_STATIC=y/" .config + make busybox + make install + cd ../../.. + + You have probably already noticed it - we are going to execute several "make" commands + and meanwhile we are going to change one property in the ".config" file. Let's go + through all of these commands: + + make clean + + The above command ensures that we will get rid of all build artefacts, assuming this + is not the first time we go through the BusyBox build process. + + make defconfig + + The above command creates new ".config" file which contains the defaults for proper + BusyBox build process. Again, nothing extraordinary here. + + sed -i "s/.*CONFIG_STATIC.*/CONFIG_STATIC=y/" .config + + The above command is very important because we inform the build process to build + static version of BusyBox, which means that the BusyBox executable file will not + be dependent on any external library. We cannot skip this, otherwise our OS will + fail with "kernel panic" when we try to boot. + + make busybox + + The above command compiles BusyBox. Nothing interesting here. The build should be + significantly faster compared to the kernel build. + + make install + + The above command creates new "_install" folder and installs BusyBox in it. We + will use this folder as a base for our new initramfs file. + + At this point we should have kernel compiled with default settings (yes, we changed + one setting but it's not a big deal) and we should also have BusyBox compiled with + static option enabled and all other default settings. + + Now we come to the part where we create our own initramfs folder which later on we + will pack into a file. The steps that we are going to follow are these: + + 1) Use the already created "_install" folder as base for initramfs. + 2) Create some new folders in the initramfs folder. + 3) Create some configuration files in the initramfs folder. + + Now we come to the script "5_generate_rootfs.sh" which is responsible to generate + proper initramfs folder with all necessary files and sub-folders in it. + + #/bin/sh + + cd work + rm -rf rootfs + cd busybox + cd $(ls -d *) + cp -R _install ../../rootfs + cd ../../rootfs + rm -f linuxrc + mkdir dev + mkdir etc + mkdir proc + mkdir src + mkdir sys + mkdir tmp + cd etc + touch welcome.txt + echo >> welcome.txt + echo ' #####################################' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' # Welcome to "Minimal Linux Live" #' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' #####################################' >> welcome.txt + echo >> welcome.txt + cd .. + touch init + echo '#!/bin/sh' >> init + echo 'dmesg -n 1' >> init + echo 'mount -t devtmpfs none /dev' >> init + echo 'mount -t proc none /proc' >> init + echo 'mount -t sysfs none /sys' >> init + echo 'cat /etc/welcome.txt' >> init + echo 'while true' >> init + echo 'do' >> init + echo ' setsid cttyhack /bin/sh' >> init + echo 'done' >> init + echo >> init + chmod +x init + cp ../../*.sh src + cp ../../.config src + cd ../.. + + As you see, this script is much longer than the others. Let's take a look at the + important parts one by one. + + cd work + rm -rf rootfs + cd busybox + cd $(ls -d *) + cp -R _install ../../rootfs + cd ../../rootfs + + The above code snippet removes the old initramfs folder called "rootfs" and then + copies the "_install" folder (the one created by BusyBox) with new name "rootfs". + This folder is going to be our new initramfs focal point. + + rm -f linuxrc + + The folder "rootfs" contains file "linuxrc" which we don't need since we are going + to use initramfs boot scheme. Take a look at the following Wikipedia article for + more details: + + http://en.wikipedia.org/wiki/Initrd + + OK, lets go on. + + mkdir dev + mkdir etc + mkdir proc + mkdir src + mkdir sys + mkdir tmp + + The above code snippet creates some basic folders which we are going to use later. + + cd etc + touch welcome.txt + echo >> welcome.txt + echo ' #####################################' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' # Welcome to "Minimal Linux Live" #' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' #####################################' >> welcome.txt + echo >> welcome.txt + cd .. + + The above code snippet creates the file "/etc/welcome.txt" and fills it with the message + which will be displayed every time we boot up the system. + + touch init + echo '#!/bin/sh' >> init + echo 'dmesg -n 1' >> init + echo 'mount -t devtmpfs none /dev' >> init + echo 'mount -t proc none /proc' >> init + echo 'mount -t sysfs none /sys' >> init + echo 'cat /etc/welcome.txt' >> init + echo 'while true' >> init + echo 'do' >> init + echo ' setsid cttyhack /bin/sh' >> init + echo 'done' >> init + echo >> init + + The above code snippet creates the file "/init" which is going to be invoked by our kernel + when we boot up the system. In fact we create new shell script file. This is what our new + "/init" script does: + + dmesg -n 1 - We hide all kernel messages. We don't want them in our + console. Only kernel panic messages will be displayed. + mount -t devtmpfs none /dev - With this command we politely ask the kernel to + populate the /dev folder with all necessary system + devices like "console", "tty", etc. We also have nice + names for the hardware devices like "sr0", "sda", etc. + mount -t proc none /proc - The kernel populates the /proc folder. + mount -t sysfs none /sys - The kernel populates the /sys folder. + cat /etc/welcome.txt - Now we display the welcome message. + while true - This code snippet starts shell on "tty" device and + setsid cttyhack /bin/sh we rest assured that when we execute the "exit" + done command new shell will be started automatically. + + As you see, the "/init" script file doesn't do much but what it does is really essential. + We have only one more bit of code relevant to the "/init" file: + + chmod +x init + + The above command ensures that our "/init" script is executable. + + cp ../../*.sh src + cp ../../.config src + + The last thing we do is to copy all "Minimal Linux Live" shell scripts (including the + configuration file) in the "/src" folder. The scripts won't do anything there. This step + simply ensures that the live Linux ISO file which we are going to create later contains + the build sources, just for reference. + + OK, at this point we have "rootfs" folder which contains all necessary files and + configurations for our initramfs file. The next step is to pack the "rootfs" folder + into an actual initramfs file. Let's take a look at "6_pack_rootfs.sh": + + #!/bin/sh + + cd work + rm -f rootfs.cpio.gz + cd rootfs + find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz + cd ../.. + + The above script removes the already existing initramfs file called "rootfs.cpio.gz" + and then creates a new file called "rootfs.cpio.gz" based on the contents of the + "rootfs" folder. + + We are almost finished. At this point we have already compiled the Linux kernel and we + have also created initramfs file based on BusyBox and our own set of configurations. + The last thing to do is to generate bootable ISO file. Let's take a look at the last + script "7_generate_iso.sh": + + #/bin/sh + + rm -f minimal_linux_live.iso + cd work/kernel + cd $(ls -d *) + make isoimage FDINITRD=../../rootfs.cpio.gz + cp arch/x86/boot/image.iso ../../../minimal_linux_live.iso + cd ../../.. + + As usual, we first remove the already generated ISO file, assuming this is not the first + time we go through this process. Then we navigate to the kernel's source folder and + we execute the following command: + + make isoimage FDINITRD=../../rootfs.cpio.gz + + The above command generates bootable ISO based on the already compiled Linux kernel and + it uses the initramfs file which we pass to the "make" command as additional parameter. + The generated ISO file is then copied to the folder where we are executing our scripts. + + ### ### ### + + 4. Possible Improvements + + Now that you have played around with your shiny new live Linux OS, you have probably + noticed that you are logged in automatically and you have no restrictions. However, + it only looks like you are automatically logged in. Yes, you get shell console and + this console allows you to perform "root" operations, but this doesn't mean that you + are logged in as "root" or any other user. In fact there are no users and groups in + the system. + + I'll show you the proper way to add some users and groups from within your system + while it is still running. You can examine the final result for yourself and modify + the "5_generate_rootfs.sh" script according to your needs. + + OK, let's go with the "root" account! + + touch /etc/group + + The above command will create empty file "/etc/group" where we store the information + for all groups. + + addgroup -g 0 root + + The above command will create a group "root" with group identification number "0". + It is important to provide 0 (zero) as group identifier (gid) because this is the + expected gid for "root". + + touch /etc/passwd + + The above command will create empty file "/etc/passwd" where we store the login + information for our users. + + adduser -h /root -G root -u 0 root + + The above command will create user "root" with home folder "/root", assign the new + user to the "root" group and set user identifier (uid) "0". It is important to + provide 0 (zero) as uid because this is the expected uid for the "root" user. Add + whatever password you want when asked. Try to remember it. + + login + + The above command will initiate the login process. Now you should be able to log in + as "root" with the password which you have provided. + + --- --- --- + + Another possible improvement is to set appropriate "global" rights (including the 't' + sticky flag) for the /tmp folder. You can do that by executing the following command: + + chmod 1777 /tmp + + The reason I haven't included this in the /init script is because in this particular + situation it doesn't really matter. By default we get uid=0 shell console and we have + full and unrestricted access to the /tmp folder. However, if you decide to add more + users to the system (not just the "root" user), you may also include the above command + in the /init script file. + + --- --- --- + + Probably the easiest update you can do is to re-compile the kernel with other than + default options. This is how we do it for the kernel. First of all we need to know + what possible options we have. Navigate to the kernel's source folder and execute the + following command: + + make help + + We have several options for interactive ".config" generation. Let's go with this one: + + make menuconfig + + You might need to resolve one more dependency ("ncurses") if you want the above command + to work. Once you do that you can choose any kernel configuration options you like. The + provided menu is quite complex but we are not in hurry. Take your time and enable or + disable any options you want. Don't forget to save your configuration. Now all we need + is to compile the new kernel. + + make vmlinux + + Depending on your configuration this time the build might take longer. Obviously if + you decide to go through manual kernel ".config" configuration you can no longer use + the script "2_build_kernel.sh" because it will override your new configuration with + the default configuration. + + --- --- --- + + Even though we haven't discussed this topic, you might have already noticed that the + file ".config" which comes along with the other build scripts contains the URL + locations for the kernel sources and the BusyBox sources. You can easily build live + Linux OS based on different kernel/BusyBox versions if you provide different + URLs in the ".config" file. Here is the content of the default ".config" file: + + # You can find the latest Linux kernel source bundles here: + # + # http://kernel.org + # + KERNEL_SOURCE_URL=https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.15.6.tar.xz + + # You can find the latest BusyBox source bundles here: + # + # http://busybox.net + # + BUSYBOX_SOURCE_URL=http://busybox.net/downloads/busybox-1.22.1.tar.bz2 + + Of course, once you do that you also need to go through the scripts "1_get_kernel.sh" + and "3_get_busybox.sh" or execute the relevant commands from these scripts manually. + + --- --- --- + + Another very interesting improvement is to execute /sbin/init and rely on further + configuration provided in /etc/inittab. Here is the modified version of the shell + script "5_generate_rootfs.sh": + + #/bin/sh + + cd work + rm -rf rootfs + cd busybox + cd $(ls -d *) + cp -R _install ../../rootfs + cd ../../rootfs + rm -f linuxrc + mkdir dev + mkdir etc + mkdir proc + mkdir src + mkdir sys + mkdir tmp + cd etc + touch bootscript.sh + echo '#!/bin/sh' >> bootscript.sh + echo 'dmesg -n 1' >> bootscript.sh + echo 'mount -t devtmpfs none /dev' >> bootscript.sh + echo 'mount -t proc none /proc' >> bootscript.sh + echo 'mount -t sysfs none /sys' >> bootscript.sh + echo >> bootscript.sh + chmod +x bootscript.sh + touch welcome.txt + echo >> welcome.txt + echo ' #####################################' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' # Welcome to "Minimal Linux Live" #' >> welcome.txt + echo ' # #' >> welcome.txt + echo ' #####################################' >> welcome.txt + echo >> welcome.txt + touch inittab + echo '::sysinit:/etc/bootscript.sh' >> inittab + echo '::restart:/sbin/init' >> inittab + echo '::ctrlaltdel:/sbin/reboot' >> inittab + echo '::once:cat /etc/welcome.txt' >> inittab + echo '::respawn:/bin/cttyhack /bin/sh' >> inittab + echo 'tty2::once:cat /etc/welcome.txt' >> inittab + echo 'tty2::respawn:/bin/sh' >> inittab + echo 'tty3::once:cat /etc/welcome.txt' >> inittab + echo 'tty3::respawn:/bin/sh' >> inittab + echo 'tty4::once:cat /etc/welcome.txt' >> inittab + echo 'tty4::respawn:/bin/sh' >> inittab + echo >> inittab + cd .. + touch init + echo '#!/bin/sh' >> init + echo 'exec /sbin/init' >> init + echo >> init + chmod +x init + cp ../../*.sh src + cp ../../.config src + cd ../.. + + The above script creates very minimal /init which executes /sbin/init. Then the + new init process (that is /sbin/init with PID 1) reads the file /etc/inittab and + executes all commands provided there. The script /etc/bootscript.sh takes care of + the initial "mount" stuff. We also have 4 terminals (you can switch between them + with "Alt + F1" to "Alt + F4") and the contents of the file /etc/welcome.txt is + displayed before we access the shell for each of these terminals. + + You can find more information about the supported /etc/inittab commands here: + + http://git.busybox.net/busybox/tree/examples/inittab + + Note that the above details are specific for BusyBox. Usually the "init" process + supports runlevels but that's not the case with BusyBox. + + --- --- --- + + Most probably you use normal user (i.e. not "root") when you execute the scripts. + One side effect is that the generated initrtamfs will keep the original ownership + of all files and folders. However, this leads to some interesting discrepancies + when you run the system. Some of the files/folders will have "root" ownership + (uid=0, gid=0) but most of the files/folders will have the same uid/gid as the + user which you used in order to build the system. This has no implications at all + since we have unrestricted shell console but if you'd like to "fix" this you will + have to either execute "5_generate_rootfs.sh" as "root" or manually change the + ownership of the initramfs folder (i.e. "work/rootfs") before you execute the + script "6_pack_rootfs.sh" with this command: + + chown -R root:root work/rootfs + + Note that the above command requires "root" permissions, so there is no way to + escape from the above described discrepancies if you don't have "root" access. + + Also note that you may need to take care of the permissions for the script files + in the "work/rootfs/src" folder. Either delete the "src" folder before you run + "6_pack_rootfs.sh" or make sure that all files have global "read" permissions. + + ### ### ### + + 5. Next Steps + + OK, now we know how to build and run a basic Linux system. But that's not enough. + Now we want to build more complex system, probably one which supports "pacman", + "apt-get", or any other package manager. + + Building such system requires a lot more work. A lot more! I mean it! + + For starters, "Minimal Linux Live" lives entirely in the "initramfs" space. Simply + said - this is the RAM space. We never really get out of there. Basically this is + what you need if you want more functional live Linux system: + + 1) Compressed file system (SquashFS)- this is where all the real stuff will be. + + 2) GNU Coreutils - these are the real shell command line utilities (ls, cd, etc.). + You need them because later we are going to "escape" from "initramfs" and use + the actual file system available in the compressed file. Alternatively, you can + overlay the whole "BusyBox" environment on top of the compressed file system but + that's not really professional approach. + + 3) You need to "switch_root" to the actual file system (the compressed one) which + you first need to locate, then mount and finally make it "writable" by overlaying + virtual RAM files/folders via UnionFS/AuFS (or something similar) if the bootable + media is not already writable. Remember that you are mounting compressed FS, which + means that if you make any changes on files located in the original FS, they will + not be persisted between reboots. Probably you want to handle this edge case. + + 4) You need to prepare in advance the stuff that you want to be present in the + compressed file system. Assuming that we are building a useful live Linux OS, the + absolute minimum is "GNU Coreutils", network management utilities and probably + some kind of package manager, e.g. "pacman" or "apt-get". Don't forget that most + of this additional stuff most probably relies on different kernel options that + also need to be enabled/configured in advance. + + 5) You need to rewrite /init and make it execute all necessary steps to fulfil point 3 + from the above. Different live Linux systems use different approaches here. + + All of the above is definitely *not* minimal but it's definitely doable if you put some + additional efforts. It will take time but as a result you will have fully functional live + Linux OS which you have created entirely by yourself. + + ### ### ### + + 6. Epilogue + + That's all folks! I hope you find this tutorial useful. And remember, we are talking + about very minimal live Linux OS here. If you want to create something bigger, I + suggest you take a look at "Linux From Scratch" (google it, you'll find it). + + At some point you may also find it useful to play around with other live Linux + distributions. Don't forget that the initramfs file is compressed and in order to + get to the actual /init script you will need to uncompress it. Then you can see + the actual file structure of the initial root file system and examine the /init + script file. This will give you more insight on the boot process for the + particular live Linux distributions that you are learning from. + + One interesting live Linux distribution is "Slax". Just download it and take a + look at the /init script file (remember, you can uncompress the initramfs file). + There is also a very good document which explains the internal root file system + and the OS boot process for Slax: + + http://slax.org/en/documentation.php#internals + + The above URL may have changed but it is valid at the time I write this document. + \ No newline at end of file