We wrote abut uClibc in this article. In this article we will build an entire Linux system using uClibc that has gcc, system utilities, a 2.4.20 kernel, and uses less than 63 megs total for the entire system. The intent is for us to write homebrew articles on a stable system that can run with minimal resources. We also don’t want to have to deal with security issues. This will run on some random piece of garbage (386, 486, Pentium), and we won’t have to have to worry so much about patching the OS/Services, since not much is running. A secondary goal is to have a system that will fit on a 100 meg zip disk. In future homebrew articles, we will use this system to compile and run our projects on.
Here is top running on our completed minimal system, just to give you an idea of how little memory is required to run a 2.4.20 Linux kernel and OS:
We will start with bare metal. No OS, nothing. This article will also provide some ideas for recovery. First, grab a copy of SuperRescue, and create a CD to boot from. We used version 2.1.2.
When you boot SuperRescue, you will see a screen like this. Push enter. When you get to the first logon screen, logon as root (no password), and type init 3. You will get a chance to log on again; do so, and type ipup. You will see a screen like this. We are on the net:
[root@localhost root]# ipup Determining IP information for eth0... done. [root@localhost root]# ifconfig eth0 Link encap:Ethernet HWaddr 00:50:56:59:00:7F inet addr:10.50.100.143 Bcast:10.50.100.255 Mask:255.255.255.0 UP BROADCAST NOTRAILERS RUNNING MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:9 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:1622 (1.5 Kb) TX bytes:2939 (2.8 Kb) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:4 errors:0 dropped:0 overruns:0 frame:0 TX packets:4 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 RX bytes:344 (344.0 b) TX bytes:344 (344.0 b) [root@localhost root]# |
Let’s create a root and swap partition, and format:
[root@localhost root]# fdisk /dev/hda Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1015, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-1015, default 1015): +900M Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 2 First cylinder (916-1015, default 916): Using default value 916 Last cylinder or +size or +sizeM or +sizeK (916-1015, default 1015): Using default value 1015 Command (m for help): t Partition number (1-4): 2 Hex code (type L to list codes): 82 Changed system type of partition 2 to 82 (Linux swap) Command (m for help): a Partition number (1-4): 1 Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: If you have created or modified any DOS 6.x partitions, please see the fdisk manual page for additional information. Syncing disks. [root@localhost root]# [root@localhost root]# mkfs.ext2 /dev/hda1 mke2fs 1.25 (20-Sep-2001) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 115456 inodes, 230572 blocks 11528 blocks (5.00%) reserved for the super user First data block=0 8 block groups 32768 blocks per group, 32768 fragments per group 14432 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 21 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. [root@localhost root]# |
Create a bzipped filesystem from root_fs-i386:
root@srv-1 u-1 # bzip2 -d root_fs-i386.bz2 root@srv-1 u-1 # mount -t ext2 -o loop ./root_fs-i386 /mnt root@srv-1 u-1 # cd /mnt root@srv-1 u-1 # tar -cjpf /tmpart/devsys.tar.bz2 * |
Mount the partition and extract the filesystem:
[root@localhost root]# mount -t ext2 /dev/hda1 /mnt [root@localhost root]# scp root@10.50.100.72:/tmpart/devsys.tar.bz2 /mnt root@10.50.100.72's password: devsys.tar.bz2 100% |*****************************| 16841 KB 00:22 [root@localhost root]# cd /mnt [root@localhost mnt]# ls devsys.tar.bz2 lost+found [root@localhost mnt]# tar -xjpf *.bz2 [root@localhost mnt]# ls bin devsys.tar.bz2 home linuxrc mnt proc sbin usr dev etc lib lost+found opt root tmp var [root@localhost mnt]# [root@localhost mnt]# rm devsys.tar.bz2 rm: remove `devsys.tar.bz2'? y [root@localhost mnt]# |
Now, we will need a kernel, among other things, so let’s start compiling a kernel on a local workstation while we are fiddling with other stuff:
u-1@srv-1 devsys $ ls linux-2.4.20.tar.gz u-1@srv-1 devsys $ tar -xzf lin*.gz u-1@srv-1 devsys $ cd lin* u-1@srv-1 linux-2.4.20 $ u-1@srv-1 linux-2.4.20 $ make xconfig u-1@srv-1 linux-2.4.20 $ make dep clean bzImage . . . System is 709 kB make[1]: Leaving directory `/home/u-1/devsys/linux-2.4.20/arch/i386/boot' u-1@srv-1 linux-2.4.20 $ |
Here is our .config file. Note that this is a trimmed down kernel without modules. Back to our uClibc box. In addition to the kernel, we will need a bootloader. We’ll use Lilo version 22.4.1 which is *not* availablehere, but newer versions are. We will also need NASM. We will use version 0.98.35 available here.
We don’t want to compile stuff using the SuperRescue filesystem stuff, so let’s chroot to our uClibc filesystem, make /boot and usr/src directories, copy the kernel, System.map, and make our symlinks in /boot:
[root@localhost proc]# chroot /mnt [root@localhost /]# mkdir /usr/src [root@localhost /]# cd /usr/src [root@localhost /]# mkdir /boot [root@localhost /]# cd /boot root@10.50.100.72's password: [root@localhost boot]# scp root@10.50.100.72:/tmpart/vmlinuz ./vmlinuz-2.4.20 root@10.50.100.72's password: vmlinuz 100% |*****************************| 701 KB 00:01 [root@localhost boot]# scp root@10.50.100.72:/tmpart/System.map ./System.map-2.4.20 root@10.50.100.72's password: System.map 100% |*****************************| 349 KB 00:00 [root@localhost boot]# ln -s vmlinuz-2.4.20 vmlinuz [root@localhost boot]# ln -s System.map-2.4.20 System.map |
Let’s compile NASM:
[root@localhost boot]# cd /usr/src root@localhost src]# scp root@10.50.100.72:/tmpart/nasm*.gz ./ root@10.50.100.72's password: nasm-0.98.35.tar.gz 100% |*****************************| 593 KB 00:00 [root@localhost src]# [root@localhost src]# tar -xzf nasm*.gz [root@localhost src]# cd nasm-0.98.35 [root@localhost nasm-0.98.35]# [root@localhost nasm-0.98.35]# ./configure --prefix=/usr checking for gcc... gcc . . . configure: creating ./config.status config.status: creating Makefile config.status: creating rdoff/Makefile config.status: creating doc/Makefile config.status: executing default-1 commands [root@localhost nasm-0.98.35]# [root@localhost nasm-0.98.35]# make gcc -c -g -O2 -Wall -ansi -pedantic -I. -I. -o nasm.o nasm.c nasm.c: In function `main': . . . make[1]: Leaving directory `/usr/src/nasm-0.98.35/rdoff' [root@localhost nasm-0.98.35]# [root@localhost nasm-0.98.35]# make install /usr/bin/install -c nasm /usr/bin/nasm /usr/bin/install -c ndisasm /usr/bin/ndisasm /usr/bin/install -c -m 644 ./nasm.1 /usr/man/man1/nasm.1 cannot create regular file `/usr/man/man1/nasm.1': No such file or directory make: *** [install] Error 1 |
The errors are because we don’t have a /usr/man directory. We are trimming this puppy down, and will use the manpages from our main workstation instead. Let’s compile Lilo and install. QuickInst will take care of both for us:
[root@localhost nasm-0.98.35]# cd /usr/src/ [root@localhost src]# scp root@10.50.100.72:/tmpart/lilo*.gz ./ root@10.50.100.72's password: lilo-22.4.1.tar.gz 100% |*****************************| 364 KB 00:00 [root@localhost src]# tar -xzf lilo*.gz [root@localhost src]# cd lilo* [root@localhost lilo-22.4.1]# [root@localhost lilo-22.4.1]# ./QuickInst QuickInst configures LILO and installs it on your hard disk. It should only be used for first-time installations, _not_ to update or modify an existing installation of LILO. It will _not_ generate a valid installation with versions of LILO below 17. The installation procedure can be interrupted by pressing ^C at any time. When at a prompt, a sub-shell can be invoked with the exclamation mark. Continue ? [yes] Replace old files ? [yes] Making LILO ... cc -E `( if [ -r $ROOT/etc/lilo.defines ]; . . . /sbin/lilo must now be run to complete the update. (Disk devices live in /dev) Gathering configuration data ... Please specify the name of the device where the LILO boot sector should be stored. (Suggested locations are the Linux root partition or the MBR of your first drive). Device name (no default) /dev/hda You are about to install LILO on your MBR. If there are other operating systems on your hard disk, LILO will act as a boot manager for them. You have to specify each operating system in your LILO configuration. (More about this later.) Please specify the name of the kernel image file you want to boot by default. Default kernel [/boot/vmlinuz] Define additional kernels ? [no] If you want to boot other operating systems than Linux from your hard disk, you should configure them now. LILO will take over the entire boot process, so any currently installed partition switchers or boot managers will stop to work. (If this scares you, just hit ^C and read the manual.) Define additional operating systems (e.g. MS-DOS) ? [no] An old version of the configuration file /etc/lilo.conf already exists. QuickInst will proceed as follows: - rename /etc/lilo.conf to /etc/lilo.conf.old - copy the new configuration file to /etc/lilo.conf Type !cat /etc/lilo.conf.tmp if you want to check the new configuration file. Proceed ? [yes] Ready to install LILO's boot sector on your hard disk. Type !cat /etc/lilo.conf if you want to check the configuration file. Test LILO installation now ? [yes] Warning: LBA32 addressing assumed Warning: COMPACT may conflict with LBA32 on some systems The boot sector and the map file have *NOT* been altered. Added linux * The following warning messages may indicate some potential problems with your configuration. The boot sector has not been changed yet. Warning: LBA32 addressing assumed Warning: COMPACT may conflict with LBA32 on some systems Install LILO now ? [yes] You see now the output of the map installer with verbose progress reporting enabled. It will list all items that are installed for booting. Additionally, if there are have been warnings, they will be repeated again. LILO version 22.4.1, Copyright (C) 1992-1998 Werner Almesberger Development beyond version 21 Copyright (C) 1999-2002 John Coffman Released 27-Jan-2003 and compiled at 23:13:30 on Mar 2 2003. Warning: LBA32 addressing assumed Warning: COMPACT may conflict with LBA32 on some systems Reading boot sector from /dev/hda Using MENU secondary loader Calling map_insert_data Boot image: /boot/vmlinuz -> vmlinuz-2.4.20 Added linux * /boot/boot.0300 exists - no backup copy made. Writing boot sector. Done. [root@localhost lilo-22.4.1]# |
Here is what our /boot directory and lilo.conf look like now:
[root@localhost lilo-22.4.1]# ls /boot System.map@ System.map-2.4.20 boot.0300 map vmlinuz@ vmlinuz-2.4.20 [root@localhost lilo-22.4.1]# cat lilo.conf lilo.conf: No such file or directory [root@localhost lilo-22.4.1]# cat /etc/lilo.conf # LILO configuration created by QuickInst 21 Sun Mar 2 23:18:31 MST 2003 boot = /dev/hda compact delay = 5 # optional, for systems that boot very quickly vga = normal # force sane state root = current # use "current" root image = /boot/vmlinuz label = linux [root@localhost lilo-22.4.1]# |
Let’s reboot this jalopy. Here is a screenshot of lilo booting the new 2.4.20 kernel. We can log on!.
We now have a complete, bootable, development system that uses less than 70 megs hard disk space. Look forward to more articles in our homebrew area that use the uClibc system. We will also document configuration and upgrades for our new uClibc system. Nothing has been configured yet. We were able to recompile the 2.4.20 kernel with this system, so it is truly self contained.