Note
The commands in the remainder of this book must be performed while logged in as user root and no longer as user lfs . Also, double check that $LFS is set in root 's environment.
Currently, the whole directory hierarchy in $LFS is owned by the user lfs , a user that exists only on the host system.
If the directories and files under $LFS are kept as they are, they will be owned by a user ID without a corresponding account. This is dangerous because a user account created later could get this same user ID and would own all the files under $LFS , thus exposing these files to possible malicious manipulation.
To address this issue, change the ownership of the $LFS/* directories to user root by running the following command:
chown --from lfs -R root:root $LFS/{usr,var,etc,tools}
case $(uname -m) in
x86_64) chown --from lfs -R root:root $LFS/lib64 ;;
esac
7.3.1. Mounting and Populating /dev
During a normal boot of an LFS system, the kernel automatically mounts the devtmpfs file system on the /dev directory; the kernel creates device nodes on that virtual file system during the boot process, or when a device is first detected or accessed.
The udev daemon may change the ownership or permissions of the device nodes created by the kernel, and create new device nodes or symlinks, to ease the work of distro maintainers and system administrators. (See Section 9.3.2.2, “Device Node Creation” for details.) If the host kernel supports devtmpfs , we can simply mount a devtmpfs at $LFS/dev and rely on the kernel to populate it.
But some host kernels lack devtmpfs support; these host distros use different methods to create the content of /dev . So the only host-agnostic way to populate the $LFS/dev directory is by bind mounting the host system's /dev directory. A bind mount is a special type of mount that makes a directory subtree or a file visible at some other location. Use the following command to do this.
mount -v --bind /dev $LFS/dev
7.3.2. Mounting Virtual Kernel File Systems
Now mount the remaining virtual kernel file systems:
mount -vt devpts devpts -o gid=5,mode=0620 $LFS/dev/pts
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
mount -vt tmpfs tmpfs $LFS/run
The meaning of the mount options for devpts:
gid=5
This ensures that all devpts-created device nodes are owned by group ID 5. This is the ID we will use later on for the tty group. We use the group ID instead of a name, since the host system might use a different ID for its tty group.
mode=0620
This ensures that all devpts-created device nodes have mode 0620 (user readable and writable, group writable).
Together with the option above, this ensures that devpts will create device nodes that meet the requirements of grantpt(), meaning the Glibc pt_chown helper binary (which is not installed by default) is not necessary.
In some host systems, /dev/shm is a symbolic link to a directory, typically /run/shm . The /run tmpfs was mounted above so in this case only a directory needs to be created with the correct permissions.
In other host systems /dev/shm is a mount point for a tmpfs. In that case the mount of /dev above will only create /dev/ shm as a directory in the chroot environment. In this situation we must explicitly mount a tmpfs:
if [ -h $LFS/dev/shm ]; then
install -v -d -m 1777 $LFS$(realpath /dev/shm)
else
mount -vt tmpfs -o nosuid,nodev tmpfs $LFS/dev/shm
fi
Note
Some of the directories mentioned in this section may have already been created earlier with explicit instructions, or when installing some packages. They are repeated below for completeness.
Create some root-level directories that are not in the limited set required in the previous chapters by issuing the following command:
mkdir -pv /{boot,home,mnt,opt,srv}
Create the required set of subdirectories below the root-level by issuing the following commands:
mkdir -pv /etc/{opt,sysconfig}
mkdir -pv /lib/firmware
mkdir -pv /media/{floppy,cdrom}
mkdir -pv /usr/{,local/}{include,src}
mkdir -pv /usr/lib/locale
mkdir -pv /usr/local/{bin,lib,sbin}
mkdir -pv /usr/{,local/}share/{color,dict,doc,info,locale,man}
mkdir -pv /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
mkdir -pv /var/{cache,local,log,mail,opt,spool}
mkdir -pv /var/lib/{color,misc,locate}
ln -sfv /run /var/run
ln -sfv /run/lock /var/lock
install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp
Directories are, by default, created with permission mode 755, but this is not desirable everywhere. In the commands above, two changes are made—one to the home directory of user root , and another to the directories for temporary files.
The first mode change ensures that not just anybody can enter the /root directory—just like a normal user would do with his or her own home directory. The second mode change makes sure that any user can write to the /tmp and /var/tmp directories, but cannot remove another user's files from them. The latter is prohibited by the so-called “sticky bit,” the highest bit (1) in the 1777 bit mask.
7.5.1. FHS Compliance Note
This directory tree is based on the Filesystem Hierarchy Standard (FHS) (available at https://refspecs.linuxfoundation.org/fhs.shtml).
The FHS also specifies the optional existence of additional directories such as /usr/local/games and /usr/share/games . In LFS, we create only the directories that are really necessary. However, feel free to create more directories, if you wish.
Warning
The FHS does not mandate the existence of the directory /usr/lib64 , and the LFS editors have decided not to use it. For the instructions in LFS and BLFS to work correctly, it is imperative that this directory be non- existent. From time to time you should verify that it does not exist, because it is easy to create it inadvertently, and this will probably break your system.
Note
The /run/utmp file records the users that are currently logged in. This file is created dynamically in the boot scripts.
Note
The utmp , wtmp , btmp , and lastlog files use 32-bit integers for timestamps and they'll be fundamentally broken after year 2038. Many packages have stopped using them and other packages are going to stop using them.
It is probably best to consider them deprecated.
7.7.1. Installation of Gettext
For our temporary set of tools, we only need to install three programs from Gettext.
Prepare Gettext for compilation:
./configure --disable-shared
The meaning of the configure option:
--disable-shared
We do not need to install any of the shared Gettext libraries at this time, therefore there is no need to build them.
Compile the package:
make
Install the msgfmt, msgmerge, and xgettext programs:cp -v gettext-tools/src/{msgfmt,msgmerge,xgettext} /usr/bin
Details on this package are located in Section 8.33.2, “Contents of Gettext.”
7.8.1. Installation of Bison
Prepare Bison for compilation:
./configure --prefix=/usr \
--docdir=/usr/share/doc/bison-3.8.2
The meaning of the new configure option:
--docdir=/usr/share/doc/bison-3.8.2
This tells the build system to install bison documentation into a versioned directory.
Compile the package:
make
Install the package:
make install
Details on this package are located in Section 8.34.2, “Contents of Bison.”
7.9.1. Installation of Perl
Prepare Perl for compilation:
sh Configure -des \
-D prefix=/usr \
-D vendorprefix=/usr \
-D useshrplib \
-D privlib=/usr/lib/perl5/5.42/core_perl \
-D archlib=/usr/lib/perl5/5.42/core_perl \
-D sitelib=/usr/lib/perl5/5.42/site_perl \
-D sitearch=/usr/lib/perl5/5.42/site_perl \
-D vendorlib=/usr/lib/perl5/5.42/vendor_perl \
-D vendorarch=/usr/lib/perl5/5.42/vendor_perl
The meaning of the Configure options:
-des
This is a combination of three options: -d uses defaults for all items; -e ensures completion of all tasks; -s silences non-essential output.
-D vendorprefix=/usr
This ensures perl knows how to tell packages where they should install their Perl modules.
-D useshrplib
Build libperl needed by some Perl modules as a shared library, instead of a static library.
-D privlib,-D archlib,-D sitelib,...
These settings define where Perl looks for installed modules. The LFS editors chose to put them in a directory structure based on the MAJOR.MINOR version of Perl (5.42) which allows upgrading Perl to newer patch levels (the patch level is the last dot separated part in the full version string like 5.42.0) without reinstalling all of the modules.
Compile the package:
make
Install the package:
make install
Details on this package are located in Section 8.43.2, “Contents of Perl.”
7.10.1. Installation of Python
Note
There are two package files whose name starts with the “python” prefix. The one to extract from is Python-3.13.7.tar.xz (notice the uppercase first letter).
Prepare Python for compilation:
./configure --prefix=/usr \
--enable-shared \
--without-ensurepip \
--without-static-libpython
The meaning of the configure option:
--enable-shared
This switch prevents installation of static libraries.
--without-ensurepip
This switch disables the Python package installer, which is not needed at this stage.
--without-static-libpython
This switch prevents building a large, but unneeded, static library.
Compile the package:
make
Note
Some Python 3 modules can't be built now because the dependencies are not installed yet. For the ssl module, a message Python requires a OpenSSL 1.1.1 or newer is outputted. The message should be ignored. Just make sure the toplevel make command has not failed. The optional modules are not needed now and they will be built in Chapter 8.
Install the package:
make install
Details on this package are located in Section 8.51.2, “Contents of Python 3.”
7.11.1. Installation of Texinfo
Prepare Texinfo for compilation:
./configure --prefix=/usr
Compile the package:
make
Install the package:
make install
Details on this package are located in Section 8.72.2, “Contents of Texinfo.”
7.12.1. Installation of Util-linux
The FHS recommends using the /var/lib/hwclock directory instead of the usual /etc directory as the location for the adjtime file. Create this directory with:
mkdir -pv /var/lib/hwclock
Prepare Util-linux for compilation:
./configure --libdir=/usr/lib \
--runstatedir=/run \
--disable-chfn-chsh \
--disable-login \
--disable-nologin \
--disable-su \
--disable-setpriv \
--disable-runuser \
--disable-pylibmount \
--disable-static \
--disable-liblastlog2 \
--without-python \
ADJTIME_PATH=/var/lib/hwclock/adjtime \
--docdir=/usr/share/doc/util-linux-2.41.1
The meaning of the configure options:
ADJTIME_PATH=/var/lib/hwclock/adjtime
This sets the location of the file recording information about the hardware clock in accordance to the FHS. This is not strictly needed for this temporary tool, but it prevents creating a file at another location, which would not be overwritten or removed when building the final util-linux package.
--libdir=/usr/lib
This switch ensures the .so symlinks targeting the shared library file in the same directory ( /usr/lib ) directly.
--disable-*
These switches prevent warnings about building components that require packages not in LFS or not installed yet.
--without-python
This switch disables using Python. It avoids trying to build unneeded bindings.
runstatedir=/run
This switch sets the location of the socket used by uuidd and libuuid correctly.
Compile the package:
make
Install the package:
make install
Details on this package are located in Section 8.79.2, “Contents of Util-linux.”
7.13.1. Cleaning
First, remove the currently installed documentation files to prevent them from ending up in the final system, and to save about 35 MB:
rm -rf /usr/share/{info,man,doc}/*
Second, on a modern Linux system, the libtool .la files are only useful for libltdl. No libraries in LFS are loaded by libltdl, and it's known that some .la files can cause BLFS package failures. Remove those files now:
find /usr/{lib,libexec} -name \*.la -delete
The current system size is now about 3 GB, however the /tools directory is no longer needed. It uses about 1 GB of disk space. Delete it now:
rm -rf /tools
7.13.2. Backup
At this point the essential programs and libraries have been created and your current LFS system is in a good state.
Your system can now be backed up for later reuse. In case of fatal failures in the subsequent chapters, it often turns out that removing everything and starting over (more carefully) is the best way to recover. Unfortunately, all the temporary files will be removed, too. To avoid spending extra time to redo something which has been done successfully, creating a backup of the current LFS system may prove useful.
Note
All the remaining steps in this section are optional. Nevertheless, as soon as you begin installing packages in Chapter 8, the temporary files will be overwritten. So it may be a good idea to do a backup of the current system as described below.
The following steps are performed from outside the chroot environment. That means you have to leave the chroot environment first before continuing. The reason for that is to get access to file system locations outside of the chroot environment to store/read the backup archive, which ought not be placed within the $LFS hierarchy.
If you have decided to make a backup, leave the chroot environment:
exit
Important
All of the following instructions are executed by root on your host system. Take extra care about the commands you're going to run as mistakes made here can modify your host system. Be aware that the environment variable LFS is set for user lfs by default but may not be set for root .
Whenever commands are to be executed by root , make sure you have set LFS .
This has been discussed in Section 2.6, “Setting the $LFS Variable and the Umask.” Before making a backup, unmount the virtual file systems:
mountpoint -q $LFS/dev/shm && umount $LFS/dev/shm
umount $LFS/dev/pts
umount $LFS/{sys,proc,run,dev}
Make sure you have at least 1 GB free disk space (the source tarballs will be included in the backup archive) on the file system containing the directory where you create the backup archive.
Note that the instructions below specify the home directory of the host system's root user, which is typically found on the root file system. Replace $HOME by a directory of your choice if you do not want to have the backup stored in root's home directory.
Note
Because the backup archive is compressed, it takes a relatively long time (over 10 minutes) even on a reasonably fast system.
Create the backup archive by running the following command:
cd $LFS
tar -cJpf $HOME/lfs-temp-tools-12.4.tar.xz .
Note
If continuing to chapter 8, don't forget to reenter the chroot environment as explained in the “Important” box below.
7.13.3. Restore
In case some mistakes have been made and you need to start over, you can use this backup to restore the system and save some recovery time. Since the sources are located under $LFS , they are included in the backup archive as well, so they do not need to be downloaded again. After checking that $LFS is set properly, you can restore the backup by executing the following commands:
Warning
The following commands are extremely dangerous. If you run rm -rf ./* as the root user and you do not change to the $LFS directory or the LFS environment variable is not set for the root user, it will destroy your entire host system. YOU ARE WARNED.
cd $LFS
rm -rf ./*
tar -xpf $HOME/lfs-temp-tools-12.4.tar.xz
Again, double check that the environment has been set up properly and continue building the rest of the system.
Important
If you left the chroot environment to create a backup or restart building using a restore, remember to check that the virtual file systems are still mounted ( findmnt | grep $LFS ).
If they are not mounted, remount them now as described in Section 7.3, “Preparing Virtual Kernel File Systems” and re-enter the chroot environment (see Section 7.4, “Entering the Chroot Environment”) before continuing.