In the previous lecture of this free Linux device drivers and embedded systems course, we established what has to exist inside a root filesystem. This lecture answers a different question: where does it all go? Linux itself does not care about directory layout — it only cares that the program named by init= or rdinit= exists. But every tool you will ever install, from BusyBox to a full package manager, silently assumes a conventional layout. That convention is the Filesystem Hierarchy Standard, and getting comfortable staging one by hand is a core skill in this free embedded Linux course.
Topics covered in this free linux kernel development course lecture
FHS directories
staging directory
bin vs sbin
rootfs skeleton
What You Will Learn
- Why Linux devices converge on a shared directory layout despite no kernel requirement to do so
- What each top-level FHS directory is actually for
- The real distinction between /bin, /sbin, and /usr
- How to stage a compliant skeleton directory by hand on your host
- How to verify your layout with the tree command
Prerequisites
This lecture builds directly on Embedded Root Filesystem Essentials from earlier in this chapter. You should know what init, shared libraries, and device nodes are for before continuing. A Linux host with a shell and the tree utility installed is all you need to follow along.
Why a Standard Layout Matters
Nothing in the kernel enforces where your shared libraries, configuration files, or device nodes live. You are technically free to put everything in one flat directory. The reason nobody does this is compatibility: the C library, every daemon you compile, and every script anyone hands you assumes paths like /etc, /lib, and /usr/bin already exist. Deviating from that convention means patching every third-party tool you ever bring onto the device. The Filesystem Hierarchy Standard (FHS) is simply the documented, agreed-upon version of that convention, and embedded systems typically implement a lean subset of it rather than the full desktop-oriented specification.
The Core FHS Directories
| Directory | Purpose |
|---|---|
| /bin | Essential programs available to every user on the system |
| /sbin | Essential programs intended for system administration |
| /dev | Device nodes and other special files |
| /etc | System-wide configuration, almost always plain text |
| /lib | Essential shared libraries, including the C library itself |
| /proc | Mount point for the proc pseudo filesystem |
| /sys | Mount point for the sysfs pseudo filesystem |
| /tmp | Temporary, volatile scratch space |
| /usr | Secondary hierarchy — /usr/bin, /usr/lib, /usr/sbin — for non-essential programs and libraries |
| /var | Files that change at runtime and may need to survive a reboot, such as logs |
The bin, sbin, and usr Distinction
Three subtleties trip up almost everyone the first time they stage a rootfs by hand:
- /bin vs /sbin — the split is not about security or permissions, it is about whether the program needs to be in a regular user’s search path. Administrative tools go in /sbin purely by convention.
- Why /usr exists at all — historically /usr could live on a separate partition or even a separate disk. Because of that, nothing required to boot the system can live exclusively under /usr; only things needed after boot belong there.
- “Essential” has a precise meaning — a file is essential if the system cannot reach a working shell prompt without it. Everything essential must live in the root partition itself, never in something mounted later.
/bin /sbin /etc /dev /lib /proc /sysPossibly separate partition (available after boot):
/usr/bin /usr/sbin /usr/libRuntime, writable, may be tmpfs or a separate partition:
/tmp /var
Hands-On: Staging Your Own Root Filesystem Tree
Let’s build a compliant skeleton from scratch on the host, using a clearly-named staging directory so it never gets confused with your host’s real root filesystem.
$ mkdir ~/ep-rootfs
$ cd ~/ep-rootfs
$ mkdir bin dev etc home lib proc sbin sys tmp usr var
$ mkdir usr/bin usr/lib usr/sbin
$ mkdir var/log var/run
Now verify the structure visually with the tree command, using -d to show directories only:
$ tree -d
# Expected output:
.
├── bin
├── dev
├── etc
├── home
├── lib
├── proc
├── sbin
├── sys
├── tmp
├── usr
│ ├── bin
│ ├── lib
│ └── sbin
└── var
├── log
└── run
14 directories
bin/ sbin/ lib/
dev/ etc/ home/
proc/ sys/ tmp/
usr/
bin/ lib/ sbin/
var/
log/ run/
At this point every directory is empty — there are no binaries, no device nodes, no configuration files yet. That is intentional and expected; this lecture is only about the shape of the tree. Populating it with a real init, BusyBox, device nodes, and configuration files is exactly what the next lectures in this chapter cover.
Real-World Use Cases
- Board bring-up — a hand-staged skeleton like this is often the very first thing you boot on new hardware, before any build system is configured
- Recovery / rescue images — deliberately minimal trees that skip /usr entirely and keep everything essential in the root partition
- Custom appliance images — teams that need a non-standard layout for regulatory or security reasons still start from this skeleton and document their deviations
Common Mistakes and Troubleshooting
Putting boot-critical binaries only in /usr
If /usr is ever mounted from a separate partition and that mount fails or is delayed, any boot-critical tool that only exists under /usr becomes unreachable. Keep truly essential binaries in /bin, /sbin, and /lib.
Forgetting /proc and /sys are mount points, not content
The directories themselves must exist in your staged tree, but they stay empty until the kernel mounts the pseudo filesystems onto them at boot. Do not try to pre-populate them.
Treating /tmp as persistent
Many embedded builds mount /tmp as tmpfs, meaning its contents vanish on every reboot. Never store anything there that needs to survive a power cycle — use /var or a dedicated data partition instead.
Best Practices
- Stage the skeleton by hand at least once, as in this lecture, before letting a build system like Buildroot or Yocto generate it for you — it makes their output far less mysterious.
- Keep the essential/non-essential boundary in mind from day one; it dictates flash partitioning decisions later.
- Document any deviation from the standard layout directly in your board support package README so future engineers are not surprised.
Performance Considerations
On flash-based storage, mounting /tmp and /var/log as tmpfs (RAM-backed) rather than on the flash filesystem directly reduces wear and typically speeds up logging-heavy workloads, at the cost of losing that data across reboots.
Summary and Key Takeaways
- The kernel enforces no directory layout — the FHS is a convention that keeps third-party tools working without modification.
- /bin vs /sbin is about search-path convention, not permissions; /usr exists specifically to hold non-essential content that can live on a separate partition.
- A staged skeleton directory is just empty folders until you populate it with binaries, libraries, device nodes, and configuration in later lectures.
Conclusion
With a compliant directory skeleton staged, the next step in this free embedded systems course is populating it with an actual init program, a shell, and the shared libraries they depend on — turning today’s empty folders into a rootfs that can genuinely boot a board.
Frequently Asked Questions
Does the kernel actually require the FHS layout?
No. The kernel only requires that the program named by init= or rdinit= exists at the path given. The FHS is a userspace convention that keeps compiled tools and scripts portable across systems.
Why does /usr sometimes live on its own partition?
Historically this let administrators separate “core system” storage from “everything else,” and it is still used today to keep a read-only base system separate from a larger, updatable application area.
Is /sbin more secure than /bin?
Not inherently. The split is about whether a program is included in a normal user’s search path, not about file permissions — actual access control still comes from standard Unix file permissions.
Do I need every FHS directory on a tiny embedded device?
No. Most embedded root filesystems implement a lean subset — commonly skipping things like /home or /media if the device has no concept of user accounts or removable media.
Should /var/log be writable in production?
Usually yes, but many teams point it at tmpfs or a dedicated log partition rather than the same flash region as the core system, so logging activity cannot wear out or corrupt boot-critical storage.
What is the next step after staging the skeleton?
Populating the tree with a real init system, a shell such as BusyBox, the C library, and device nodes — each covered in the following lectures of this chapter.
Continue This Free Linux Development Course
Next up: populating this skeleton with BusyBox, device nodes, and a working init system.
