A Gentle Introduction to UNIX
This chapter provides a hands-on introduction to UNIX and FreeBSD basics.
Chapter 3: A Gentle Introduction to UNIX
Now that your FreeBSD system is installed and running, it's time to get comfortable living inside it. FreeBSD isn't just an operating system, it's part of a long tradition that started with UNIX more than fifty years ago.
In this chapter, we'll take our first real tour of the system. You'll learn how to navigate the filesystem, run commands in the shell, manage processes, and install applications. Along the way, you'll see how FreeBSD inherits the UNIX philosophy of simplicity and consistency, and why that matters for us as future driver developers.
Think of this chapter as your survival guide for working inside FreeBSD. Before we start diving into C code and kernel internals, you'll need to be comfortable moving around the system, manipulating files, and using the tools that every developer relies on daily.
By the end of this chapter, you won't just know what UNIX is; you'll be using FreeBSD confidently as both a user and an aspiring systems programmer.
Reader Guidance: How to Use This Chapter
This chapter is not just something to skim, it's designed to be both a reference and a hands-on bootcamp. How long it takes depends on how you approach it:
- Reading only: About 2 hours to go through the text and examples at a comfortable beginner's pace.
- Reading + labs: About 4 hours if you pause to type and run each of the hands-on labs in your own FreeBSD system.
- Reading + challenges: About 6 hours or more if you also complete the full set of 46 challenge exercises at the end.
Recommendation: Don't try to do everything in one sitting. Break the chapter into sections, and after each one, run the lab before moving on. Save the challenges for when you feel confident and want to test your mastery.
3.1 Introduction: Why UNIX Matters
Before we start writing device drivers for FreeBSD, we need to pause and talk about the foundation they stand on: UNIX.
Every driver you'll ever write for FreeBSD, every system call you'll explore, every kernel message you'll read, they all make sense only when you understand the operating system they live in. For a beginner, the world of UNIX can feel mysterious, filled with odd commands and a very different philosophy compared to Windows or macOS. But once you learn its logic, you'll see it's not only approachable but also elegant and incredibly powerful.
This chapter is about giving you a gentle introduction to UNIX as it appears in FreeBSD. By the end, you'll feel comfortable navigating the system, working with files, running commands, managing processes, installing applications, and even writing small scripts to automate your tasks. These are everyday skills for any FreeBSD developer and absolutely essential before we dive into kernel development.
Why Should You Learn UNIX Before Writing Drivers?
Think of it like this: if writing drivers is like building an engine, UNIX is the entire car around it. You need to know where the fuel goes, how the dashboard works, and what the controls do before you can safely swap parts under the hood.
Here are a few reasons why learning UNIX basics is essential:
- Everything in UNIX is connected. Files, devices, processes, they all follow consistent rules. Once you know these rules, the system becomes predictable.
- FreeBSD is a direct descendant of UNIX. The commands, filesystem layout, and overall philosophy are not add-ons; they are part of its DNA.
- Drivers integrate with userland. Even though your code will run in the kernel, it will interact with user programs, files, and processes. Understanding the userland environment helps you design drivers that feel natural and intuitive.
- Debugging requires UNIX skills. When your driver misbehaves, you'll rely on tools like
dmesg
,sysctl
, and shell commands to figure out what's happening.
What You Will Learn in This Chapter
By the end of this chapter, you will:
- Understand what UNIX is and how FreeBSD fits into its family.
- Be able to use the shell to run commands and manage files.
- Navigate the FreeBSD filesystem and know where things live.
- Manage users, groups, and file permissions.
- Monitor processes and system resources.
- Install and remove applications using FreeBSD's package manager.
- Automate tasks with shell scripts.
- Peek into FreeBSD internals with tools like
dmesg
andsysctl
.
All along the way, I'll give you hands-on labs so you can practice. Reading about UNIX is not enough; you need to touch the system. Each lab will involve real commands you'll run on a FreeBSD installation, so by the time you reach the end of this chapter, you won't just understand UNIX, you'll be using it confidently.
The Bridge to Device Drivers
Why are we spending an entire chapter on UNIX basics if this is a book about writing drivers? Because drivers don't exist in isolation. When you eventually load your own kernel module, you'll see it appear under /dev
. When you test it, you'll use shell commands to read and write to it. When you debug it, you'll rely on system logs and monitoring tools.
So think of this chapter as laying down the operating system literacy you need before becoming a driver developer. Once you have it, everything else will feel less intimidating and far more logical.
Wrapping Up
In this opening section, we looked at why UNIX matters for anyone who wants to write FreeBSD drivers. Drivers don't live in isolation; they exist inside a larger operating system that follows rules, conventions, and a philosophy inherited from UNIX. Understanding this foundation is what makes everything else, from using the shell to debugging drivers, logical instead of mysterious.
With that motivation in mind, it's time to ask the natural next question: what exactly is UNIX? To move forward, we'll take a closer look at its history, its guiding principles, and the key concepts that still shape FreeBSD today.
3.2 What Is UNIX?
Before you can get comfortable using FreeBSD, it helps to understand what UNIX is and why it matters. UNIX isn't just a piece of software, it's a family of operating systems, a set of design choices, and even a philosophy that has shaped computing for more than fifty years. FreeBSD is one of its most important modern descendants, so learning UNIX is like studying the family tree to see where FreeBSD fits.
A Brief History of UNIX
UNIX was born in 1969 at Bell Labs, when Ken Thompson and Dennis Ritchie created a lightweight operating system for a PDP-7 minicomputer. At a time when mainframes were huge, costly, and complex, UNIX stood out because it was small, elegant, and designed for experimentation.
The 1973 rewrite in C was the turning point. For the first time, an operating system was portable: you could move UNIX to different hardware by recompiling it, not by rewriting everything from scratch. This was unheard of in the 1970s and changed the trajectory of system design forever.
BSD at Berkeley is the part of the story that leads directly to FreeBSD. Graduate students and researchers at the University of California, Berkeley, took AT&T's UNIX source code and extended it with modern features:
- Virtual memory (so programs weren't limited by physical RAM).
- Networking (the TCP/IP stack that still powers the internet today).
- The C shell with scripting and job control.
In the 1990s, after legal disputes over UNIX source code were resolved, the FreeBSD Project was launched. Its mission: to carry the BSD tradition forward, freely and openly, for anyone to use, modify, and share.
Today, FreeBSD is a direct continuation of that lineage. It is not a UNIX imitation; it is UNIX heritage alive and well.
You might be thinking, "Why should I care?". You should because when you peek into /usr/src
or type commands like ls
and ps
, you're not just using software, you're benefiting from decades of problem-solving and craftsmanship, the work of thousands of developers who built and polished these tools long before you.
The UNIX Philosophy
UNIX is not only a system; it's a mindset. Understanding its philosophy will make everything else, from basic commands to device drivers, feel more natural.
-
Do one thing, and do it well. Instead of giant, all-in-one programs, UNIX gives you focused tools.
Example:
grep
only searches text. It doesn't open files, edit them, or format results; it leaves that to other tools. -
Everything is a file. Files are not just documents; they are the way you interact with almost everything: devices, processes, sockets, logs.
Analogy: Think of the entire system as a library. Every book, desk, and even the librarian's notebook is part of the same filing system.
-
Build small tools, then combine them. This is the genius of the pipe operator (
|
). You take the output of one program and use it as the input for another.Example:
ps -aux | grep ssh
Here, one program lists all processes, and another filters only the ones related to SSH. Neither program knows about the other, but the shell glues them together.
-
Use plain text whenever possible. Text files are easy to read, edit, share, and debug. FreeBSD's
/etc/rc.conf
(system configuration) is just a plain text file. No binary registries, no proprietary formats.
When you start writing device drivers, you'll see this philosophy everywhere: your driver will expose a simple interface under /dev
, behave predictably, and integrate smoothly with other tools.
UNIX-like Systems Today
The word "UNIX" today refers less to a single operating system and more to a family of UNIX-like systems.
- FreeBSD - Your focus in this book. Used in servers, networking gear, firewalls, and embedded systems. Known for reliability and documentation. Many commercial appliances (routers, storage systems) silently run FreeBSD under the hood.
- Linux - Created in 1991, inspired by UNIX principles. Popular in data centers, embedded devices, and supercomputers. Unlike FreeBSD, Linux is not a direct UNIX descendant but shares the same interface and ideas.
- macOS and iOS - Built on Darwin, a BSD-based foundation. macOS is a UNIX-certified OS, meaning its command line tools behave like FreeBSD's. If you use a Mac, you already have a UNIX system.
- Others - Commercial variants like AIX, Solaris, or HP-UX still exist but are rare outside enterprise contexts.
Why this matters: Once you learn FreeBSD, you'll feel comfortable on almost any other UNIX-like system. The commands, filesystem layout, and philosophy all carry over.
Key Concepts and Terms
Here are some essential UNIX terms you'll see throughout this book:
- Kernel - The heart of the OS. It manages memory, CPU, devices, and processes. Your drivers will live here.
- Shell - The program that interprets your commands. It's your main tool for talking to the system.
- Userland - Everything outside the kernel: commands, libraries, daemons. It's where you'll spend most of your time as a user.
- Daemon - A background service (like
sshd
for remote logins orcron
for scheduled tasks). - Process - A running program. Each command creates a process.
- File descriptor - A numeric handle that the kernel gives programs to work with files or devices. For example, 0 = standard input, 1 = standard output, 2 = standard error.
Tip: Don't worry about memorizing these yet. Think of them as characters you'll meet again later in the story. By the time you write a driver, you'll know them like old friends.
How UNIX Differs from Windows
If you've mostly used Windows, the UNIX approach will feel different at first. Here are a few contrasts:
- Drives vs. unified tree
Windows uses drive letters (
C:\
,D:\
). UNIX has a single tree rooted at/
. Disks and partitions are mounted into this tree. - Registry vs. text files
Windows centralizes settings in the Registry. UNIX uses plain-text configuration files under
/etc
and/usr/local/etc
. You can open them with any text editor. - GUI focus vs. CLI focus While Windows assumes a graphical interface, UNIX treats the command line as the primary tool. Graphical environments exist, but the shell is always available and powerful.
- Permissions model UNIX was multi-user from day one. Every file has permissions (read, write, execute) for the owner, group, and others. This makes security and sharing simpler and more consistent.
These differences explain why UNIX often feels "stricter" but also more transparent. Once you get used to it, the consistency becomes a huge advantage.
Everyday UNIX in Your Life
Even if you've never logged into a FreeBSD system before, UNIX is already around you:
- Your Wi-Fi router or NAS may run FreeBSD or Linux.
- Netflix uses FreeBSD servers to deliver streaming video.
- Sony's PlayStation uses a FreeBSD-based OS.
- macOS and iOS are direct descendants of BSD UNIX.
- Android phones run Linux, another UNIX-like system.
Learning FreeBSD is not just about writing drivers, it's about learning the language of modern computing.
Hands-On Lab: Your First UNIX Commands
Let's make this concrete. Open a terminal in the FreeBSD you installed in the previous chapter and try:
% uname -a
This prints system details: the OS, the system name, release version, kernel build, and machine type. On FreeBSD 14.x, you might see:
FreeBSD freebsd.edsonbrandi.com 14.3-RELEASE FreeBSD 14.3-RELEASE releng/14.3-n271432-8c9ce319fef7 GENERIC amd64
Now try the commands:
% date
% whoami
% hostname
date
- shows the current time and date.whoami
- tells you which user account you're logged in as.hostname
- shows the machine's network name.
Finally, a small experiment with UNIX's "everything is a file" idea:
% echo "Hello FreeBSD" > /tmp/testfile
% cat /tmp/testfile
You just created a file, wrote to it, and read it back. This is the same model you'll later use to talk to your own drivers.
Wrapping Up
In this section, you learned that UNIX is not just an operating system but a family of ideas and design principles that shaped modern computing. You saw how FreeBSD fits into this history as a direct descendant of BSD UNIX, why its philosophy of small tools and plain text makes it powerful, and how many of the concepts you'll rely on as a driver developer, like processes, daemons, and file descriptors, have been part of UNIX since the beginning.
But knowing what UNIX is only gets us halfway. To really use FreeBSD, you need a way to interact with it. That's where the shell comes in, the command interpreter that lets you speak the system's language. In the next section, we'll start using the shell to run commands, explore the filesystem, and get hands-on experience with the tools that every FreeBSD developer depends on daily.
3.3 The Shell: Your Window Into FreeBSD
Now that you know what UNIX is and why it matters, it's time to start talking to the system. The way you do that in FreeBSD (and other UNIX-like systems) is through the shell.
Think of the shell as both an interpreter and a translator: you type a command in human-readable form, and the shell passes it to the operating system to execute. It's the window between you and the UNIX world.
What Is a Shell?
At its core, the shell is just a program, but a very special one. It listens to what you type, figures out what you mean, and asks the kernel to carry it out.
Some common shells include:
- sh - The original Bourne shell. Simple and reliable.
- csh / tcsh - The C shell and its enhanced version, with scripting features inspired by the C language. tcsh is FreeBSD's default for new users.
- bash - The Bourne Again Shell, very popular in Linux.
- zsh - A modern, user-friendly shell with many conveniences.
On FreeBSD 14.x, if you log in as a normal user, you'll probably be using tcsh. If you log in as the root administrator, you may see sh. Don't worry if you're not sure which shell you have, we'll cover how to check in just a moment.
Why this matters for driver developers: you'll use the shell constantly to compile, load, and test your drivers. Knowing how to navigate it is as important as knowing how to turn the ignition key in a car.
How to Know Which Shell You're Using
FreeBSD comes with more than one shell, and you might notice slight differences between them, for example, the prompt might look different, or certain shortcuts might behave differently. Don't worry: the core UNIX commands work the same no matter which shell you're in. Still, it's helpful to know which shell you're currently using, especially if you later decide to write scripts or customize your environment.
Type:
% echo $SHELL
You'll see something like:
/bin/tcsh
or
/bin/sh
This tells you your default shell. You don't need to change it now; just be aware that shells may look slightly different but share the same basic commands.
Hands-On Tip There's also a quick way to check which shell is running for your current process:
% echo $0
This may show -tcsh
, sh
, or something else. It's slightly different from $SHELL
, because $SHELL
tells you your default shell (the one you get when you log in), while $0
tells you the shell you're actually running right now. If you ever start a different shell inside your session (for example by typing sh
at the prompt), $0
will reflect that.
The Structure of a Command
Every shell command follows the same simple pattern:
command [options] [arguments]
- command - The program you want to run.
- options - Flags that change how it behaves (usually starting with
-
). - arguments - The targets of the command, like filenames or directories.
Example:
% ls -l /etc
ls
= list directory contents.-l
= option for "long format."/etc
= argument (the directory to list).
This consistency is one of UNIX's strengths: once you learn the pattern, every command feels familiar.
Essential Commands for Beginners
Let's explore the core commands you'll use constantly.
Navigating Directories
-
pwd - Print Working Directory Shows where you are in the filesystem.
% pwd
Output:
/home/dev
-
cd - Change Directory Moves you into another directory.
% cd /etc % pwd
Output:
/etc
-
ls - List Shows the contents of a directory.
% ls
Output might include:
rc.conf ssh/ resolv.conf
Tip: Try ls -lh
for human-readable file sizes.
Managing Files and Directories
-
mkdir - Make Directory
% mkdir projects
-
rmdir - Remove Directory (only if empty)
% rmdir projects
-
cp - Copy
% cp file1.txt file2.txt
-
mv - Move (or rename)
% mv file2.txt notes.txt
-
rm - Remove (delete)
% rm notes.txt
Warning: rm
does not ask for confirmation. Once removed, the file is gone unless you have a backup. This is a common beginner pitfall.
Viewing File Contents
-
cat - Concatenate and display file contents
% cat /etc/rc.conf
-
less - View file contents with scrolling
% less /etc/rc.conf
Use arrow keys or spacebar, press
q
to quit. -
head / tail - Show the beginning or end of a file,
-n
parameter specifies the number of lines you want to see% head -n 5 /etc/rc.conf % tail -n 5 /etc/rc.conf
Editing Files
Sooner or later, you'll need to edit a configuration file or a source file. FreeBSD ships with a few editors, each with different strengths:
-
ee (Easy Editor)
- Installed by default.
- Designed to be beginner-friendly, with visible menus at the top of the screen.
- To save, press Esc, then choose "Leave editor" → "Save changes."
- Great choice if you've never used a UNIX editor before.
-
vi / vim
- The traditional UNIX editor, always available.
- Extremely powerful, but it has a steep learning curve.
- Beginners often get stuck because
vi
starts in command mode instead of insert mode. - To start typing text: press i, write your text, then press Esc followed by
:wq
to save and quit. - You don't need to master it now, but every sysadmin and developer eventually learns at least the basics of
vi
.
-
nano
-
Not part of the FreeBSD base system, but can be installed easily running the following command while logged as root:
# pkg install nano
-
Very beginner-friendly, with shortcuts listed at the bottom of the screen.
-
If you're coming from Linux distributions like Ubuntu, you may already know it.
-
Tip for Beginners
Start with ee
to get comfortable editing files on FreeBSD. Once you're ready, learn the basics of vi
, it will always be there for you, even in rescue environments or minimal systems where nothing else is installed.
Hands-On Lab: Your First Edits
-
Create and edit a new file with
ee
:% ee hello.txt
Write a short line of text, save, and exit.
-
Try the same with
vi
:% vi hello.txt
Press
i
to insert, type something new, then pressEsc
and type:wq
to save and quit. -
If you installed
nano
:% nano hello.txt
Notice how the bottom line shows commands like
^O
for save and^X
for exit.
Common Beginner Pitfall: Stuck in vi
Almost every UNIX beginner has faced this: you open a file with vi
, start pressing keys, and nothing happens the way you expect. Worse, you can't figure out how to quit.
Here's what's happening:
vi
starts in command mode, not typing mode.- To insert text, press i (insert).
- To return to command mode, press Esc.
- To save and quit: type
:wq
and press Enter. - To quit without saving: type
:q!
and press Enter.
Tip: If you accidentally open vi
and just want to escape, press Esc, type :q!
, and hit Enter. That will exit without saving.
Tips and Shortcuts
Once you get comfortable typing commands, you'll quickly discover that the shell has many built-in features to save time and reduce mistakes. Learning these early will make you feel at home much faster.
Note about FreeBSD shells:
- The default login shell for new users is usually
/bin/tcsh
, which supports tab completion, history navigation with arrow keys, and many interactive shortcuts. - The more minimal
/bin/sh
shell is excellent for scripting and system use, but it does not provide conveniences like tab completion or arrow-key history out of the box. - So if some shortcuts below don't seem to work, check which shell you are using (
echo $SHELL
).
Tab completion (tcsh)
Start typing a command or filename and press Tab
. The shell will try to complete it for you.
% cd /et<Tab>
Becomes:
% cd /etc/
If there's more than one match, press Tab
twice to see a list of possibilities.
This feature is not available in /bin/sh
.
Command history (tcsh)
Press the Up arrow to recall the last command, and keep pressing it to walk further back in time. Press the Down arrow to move forward again.
% sysctl kern.hostname
You don't have to retype it, just hit the Up arrow and press Enter.
In /bin/sh
, you don't get arrow-key navigation (but you can still run commands again with !!
).
Wildcards (globbing)
Works in all shells, including /bin/sh
.
% ls *.conf
Lists all files that start with host
and end with .conf
.
% ls host?.conf
Matches files like host1.conf
, hostA.conf
, but not hosts.conf
.
Editing on the command line (tcsh)
In tcsh
you can move the cursor left and right with arrow keys, or use shortcuts:
-
Ctrl+A → Move to the beginning of the line.
-
Ctrl+E → Move to the end of the line.
-
Ctrl+U → Erase everything from the cursor to the start of the line.
-
Repeating commands quickly (all shells)
% !!
Re-executes your last command.
% !ls
Repeats the last command that started with
ls
.
Tip: If you want a friendlier interactive shell, stick with /bin/tcsh
(the FreeBSD default for users). If you later want advanced customization, you can install shells like bash
or zsh
from packages or ports. But for scripting, always use /bin/sh
, since it's guaranteed to be present and is the system's standard.
Hands-On Lab: Navigating and Managing Files
Let's practice:
-
Go to your home directory:
% cd ~
-
Create a new directory:
% mkdir unix_lab % cd unix_lab
-
Create a new file:
% echo "Hello FreeBSD" > hello.txt
-
View the file:
% cat hello.txt
-
Make a copy:
% cp hello.txt copy.txt % ls
-
Rename it:
% mv copy.txt renamed.txt
-
Delete the renamed file:
% rm renamed.txt
By completing these steps, you've just navigated the filesystem, created files, copied them, renamed them, and removed them, the daily bread and butter of UNIX work.
Wrapping Up
The shell is your gateway into FreeBSD. Every interaction with the system, whether running commands, compiling code, or testing a driver, flows through it. In this section, you learned what the shell is, how commands are structured, and how to perform basic navigation and file management.
Next, we'll explore how FreeBSD organizes its filesystem. Understanding the layout of directories like /etc
, /usr
, and /dev
will give you a mental map of the system, which is especially important when we start dealing with device drivers that live under /dev
.
3.4 The FreeBSD Filesystem Layout
In Windows, you may be used to drives like C:\
and D:\
. In UNIX and FreeBSD, there are no drive letters. Instead, everything lives in a single tree of directories that starts at the root /
.
This is called a hierarchical filesystem. At the very top is /
, and everything else branches out beneath it like folders inside folders. Devices, configuration files, and user data are all organized inside this tree.
Here's a simplified map:
/
├── bin → Essential user commands (ls, cp, mv)
├── sbin → System administration commands (ifconfig, shutdown)
├── etc → Configuration files
├── usr
│ ├── bin → Non-essential user commands
│ ├── sbin → Non-essential system admin tools
│ ├── local → Software installed by pkg or ports
│ └── src → FreeBSD source code
├── var → Logs, mail, spools, temp runtime data
├── home → User home directories
├── dev → Device files
└── boot → Kernel and boot loader
And here's a table with some of the most important directories you'll work with:
Directory | Purpose |
---|---|
/ | Root of the entire system. Everything begins here. |
/bin | Essential command-line tools (used during early boot). |
/sbin | System binaries (like init , ifconfig ). |
/usr/bin | User command-line tools and programs. |
/usr/sbin | System-level tools used by administrators. |
/usr/src | FreeBSD source code (kernel, libraries, drivers). |
/usr/local | Where packages and installed software go. |
/boot | Kernel and boot loader files. |
/dev | Device nodes, files that represent devices. |
/etc | System configuration files. |
/home | User home directories (like /home/dev ). |
/var | Log files, mail spools, runtime files. |
/tmp | Temporary files, cleared on reboot. |
Understanding this layout is critical for a driver developer because some directories, especially /dev
, /boot
, and /usr/src
, are directly tied to the kernel and drivers. But even outside of those, knowing where things live helps you navigate confidently.
Base system vs local software: One key idea in FreeBSD is the separation between the base system and user-installed software. The base system: kernel, libraries, and essential tools live in /bin
, /sbin
, /usr/bin
, and /usr/sbin
. Everything you install later with pkg or ports goes into /usr/local
. This separation keeps your core OS stable while letting you add and update software freely.
Devices as Files: /dev
One of UNIX's most powerful ideas is that devices appear as files under /dev
.
Examples:
/dev/null
: A "black hole" that discards anything you write to it./dev/zero
: Outputs an endless stream of zero bytes./dev/random
: Provides random data./dev/ada0
: Your first SATA disk./dev/da0
: A USB storage device./dev/tty
: Your terminal.
You can interact with these devices using the same tools you use for files:
% echo "test" > /dev/null
% head -c 10 /dev/zero | hexdump
Later in this book, when you create a driver, it will expose a file here, for example, /dev/hello
. Writing to that file will actually run your driver's code inside the kernel.
Absolute vs. Relative Paths
When navigating the filesystem, paths can be:
- Absolute - Start at the root
/
. Example:/etc/rc.conf
- Relative - Start from your current location. Example:
../notes.txt
Example:
% cd /etc # absolute path
% cd .. # relative path: move up one directory
Remember: /
always means the root of the system, while .
means "here" and ..
means "one level up."
Example: Navigating with Absolute vs Relative Paths
Suppose your home directory contains this structure:
/home/dev/unix_lab/
├── docs/
│ └── notes.txt
├── code/
│ └── test.c
└── tmp/
-
To open
notes.txt
with an absolute path:% cat /home/dev/unix_lab/docs/notes.txt
-
To open it with a relative path from inside
/home/dev/unix_lab
:% cd /home/dev/unix_lab % cat docs/notes.txt
-
Or, if you are already inside the
docs
directory:% cd /home/dev/unix_lab/docs % cat ./notes.txt
Absolute paths always work, no matter where you are, while relative paths depend on your current directory. As a developer, you'll often prefer absolute paths in scripts (more predictable) and relative paths when working interactively (faster to type).
Hands-On Lab: Exploring the Filesystem
Let's practice exploring FreeBSD's layout:
- Print your current location:
% pwd
-
Go to the root directory and list its contents:
% cd / % ls -lh
-
Peek into the
/etc
directory:% ls /etc % head -n 5 /etc/rc.conf
-
Explore
/var/log
and view system logs:% ls /var/log % tail -n 10 /var/log/messages
-
Check devices under
/dev
:% ls /dev | head
This lab gives you a "mental map" of the FreeBSD filesystem and shows how configuration files, logs, and devices are all organized in predictable places.
Wrapping Up
In this section, you've learned that FreeBSD uses a single, hierarchical filesystem starting at /
, with key directories dedicated to system binaries, configuration, logs, user data, and devices. You also saw how /dev
treats devices as files, a powerful concept that you'll rely on when you write drivers.
But files and directories aren't just about structure; they're also about who can access them. UNIX is a multi-user system, and every file has an owner, a group, and permission bits that control what can be done with it. In the next section, we'll explore users, groups, and permissions, and you'll learn how FreeBSD keeps the system both secure and flexible.
3.5 Users, Groups, and Permissions
One of the biggest differences between UNIX and systems like early Windows is that UNIX was designed from the beginning as a multi-user operating system. That means it assumes multiple people (or services) can use the same machine at once, and it enforces rules about who can do what.
This design is essential for security, stability, and collaboration, and as a driver developer, you'll need to understand it well, because permissions often control who can access your driver's device file.
Users and Groups
Every person or service that uses FreeBSD does so under a user account.
- A user has a username, a numeric ID (UID), and a home directory.
- A group is a collection of users, identified by a group name and group ID (GID).
Each user belongs to at least one group, and permissions can be applied both to individuals and to groups.
You can see your current identity with:
% whoami
% id
Example output:
dev
uid=1001(dev) gid=1001(dev) groups=1001(dev), 0(wheel)
Here:
- Your username is
dev
. - Your UID is
1001
. - Your primary group is
dev
. - You also belong to the
wheel
group, which allows access to administrative privileges (viasu
orsudo
).
File Ownership
In FreeBSD, every file and directory has an owner (a user) and a group.
Let's check with ls -l
:
% ls -l hello.txt
Output:
-rw-r--r-- 1 dev dev 12 Aug 23 10:15 hello.txt
Breaking it down:
-rw-r--r--
= permissions (we'll cover in a moment).1
= number of links (not important for now).dev
= owner (the user who created the file).dev
= group (the group associated with the file).12
= file size in bytes.Aug 23 10:15
= last modification time.hello.txt
= filename.
So this file belongs to user dev
and group dev
.
Permissions
Permissions control what users can do with files and directories. There are three categories of users:
- Owner - the user who owns the file.
- Group - members of the file's group.
- Others - everyone else.
And three kinds of permission bits:
- r = read (can view contents).
- w = write (can modify or delete).
- x = execute (for programs or, in directories, the ability to enter them).
Example:
-rw-r--r--
This means:
- Owner = read + write.
- Group = read only.
- Others = read only.
So the owner can modify the file, but everyone else can only look at it.
Changing Permissions
To modify permissions, you use the chmod command.
Two ways:
Symbolic mode
% chmod u+x script.sh
This adds execute permission (+x
) for the user (u
).
Octal mode
% chmod 755 script.sh
Here, numbers represent permissions:
- 7 = rwx
- 5 = r-x
- 0 = ---
So 755
means: owner = rwx, group = r-x, others = r-x.
Changing Ownership
Sometimes you need to change who owns a file. Use chown
:
% chown root:wheel hello.txt
Now the file is owned by root and the group wheel.
Note: Changing ownership usually requires administrator privileges.
Practical Scenario: Project Directory
Suppose you're working on a project with a teammate, and you both need access to the same files.
Here's how you'd set it up, run these commands as root:
-
Create a group called
proj
:# pw groupadd proj
-
Add both users to the group:
# pw groupmod proj -m dev,teammate
-
Create a directory and assign it to the group:
# mkdir /home/projdir # sudo chown dev:proj /home/projdir
-
Set group permissions so members can write:
# chmod 770 /home/projdir
Now both users can work in /home/projdir
, while others cannot access it.
This is exactly how UNIX systems enforce collaboration securely.
Hands-On Lab: Permissions in Action
Let's practice:
-
Create a new file:
% echo "secret" > secret.txt
-
Check its default permissions:
% ls -l secret.txt
-
Remove read access for others:
% chmod o-r secret.txt % ls -l secret.txt
-
Add execute permission for the user:
% chmod u+x secret.txt % ls -l secret.txt
-
Try to change ownership (will require root):
% sudo chown root secret.txt % ls -l secret.txt
Beware that sudo
will ask for your password to execute the command chown
above in the step 5.
With these commands, you've controlled access to files at a very fine level, a concept that applies directly when we create drivers, since drivers also have device files under /dev
with ownership and permission rules.
Wrapping Up
In this section, you learned that FreeBSD is a multi-user system where every file has an owner, a group, and permission bits that control access. You saw how to inspect and change permissions, how to manage ownership, and how to set up collaboration safely with groups.
These rules may seem simple, but they are the backbone of FreeBSD's security model. Later, when you write drivers, your device files under /dev
will also have ownership and permissions, controlling who can open and use them.
Next, we'll look at processes, the running programs that make the system alive. You'll learn how to see what's running, how to manage processes, and how FreeBSD keeps everything organized behind the scenes.
3.6 Processes and System Monitoring
So far, you've learned how to navigate the filesystem and manage files. But an operating system isn't just about files on disk; it's about programs running in memory. These running programs are called processes, and understanding them is essential for both daily use and driver development.
What Is a Process?
A process is a program in motion. When you run a command like ls
, FreeBSD:
- Loads the program into memory.
- Assigns it a process ID (PID).
- Gives it resources like CPU time and memory.
- Tracks it until it finishes or is stopped.
Processes are how FreeBSD manages everything that happens on your system. From the shell you type into, to daemons in the background, to your web browser, they're all processes.
For driver developers: When you write a driver, processes in userland will talk to it. Knowing how processes are created and managed helps you understand how drivers are used.
Foreground vs. Background Processes
Usually, when you run a command, it runs in the foreground, meaning you can't do anything else in that terminal until it finishes.
Example:
% sleep 10
This command pauses for 10 seconds. During that time, your terminal is "blocked."
To run a process in the background, add an &
at the end:
% sleep 10 &
Now you get your prompt back immediately, and the process runs in the background.
You can see background jobs with:
% jobs
And bring one back to the foreground:
% fg %1
(where %1
is the job number in the list you see with jobs
).
Viewing Processes
To see which processes are running, use ps
:
ps aux
Sample output:
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
root 1 0.0 0.0 1328 640 - Is 10:00AM 0:00.01 /sbin/init
dev 1024 0.0 0.1 4220 2012 - S 10:05AM 0:00.02 -tcsh
dev 1055 0.0 0.0 1500 800 - R 10:06AM 0:00.00 ps aux
Here:
PID
= process ID.USER
= who started it.%CPU
/%MEM
= resources being used.COMMAND
= the program running.
Watching Processes and System Load with top
While ps
gives you a snapshot of processes at a single moment, sometimes you want a live view of what's happening on your system. That's where the top
command comes in.
% top
This opens a continuously updating display of system activity. By default, it refreshes every 2 seconds. To quit, press q.
The top
screen shows:
- Load averages (how busy your system is, averaged over 1, 5, and 15 minutes).
- Uptime (how long the system has been running).
- CPU usage (user, system, idle).
- Memory and swap usage.
- A list of processes, sorted by CPU usage, so you can see which programs are working hardest.
Example of top
Output (simplified):
last pid: 3124; load averages: 0.06, 0.12, 0.14 up 0+20:43:11 11:45:09
17 processes: 1 running, 16 sleeping
CPU: 0.0% user, 0.0% nice, 0.0% system, 0.0% interrupt, 100% idle
Mem: 5480K Active, 1303M Inact, 290M Wired, 83M Buf, 387M Free
Swap: 1638M Total, 1638M Free
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
3124 dev 1 20 0 15M 3440K CPU3 3 0:00 0.03% top
2780 dev 1 20 0 23M 11M select 0 0:00 0.01% sshd-session
639 root 1 20 0 14M 2732K select 2 0:02 0.00% syslogd
435 root 1 20 0 15M 4012K select 2 0:04 0.00% devd
730 root 1 20 0 14M 2612K nanslp 0 0:00 0.00% cron
697 root 2 20 0 18M 4388K select 3 0:00 0.00% qemu-ga
2778 root 1 20 0 23M 11M select 1 0:00 0.00% sshd-session
726 root 1 20 0 23M 9164K select 3 0:00 0.00% sshd
760 root 1 68 0 14M 2272K ttyin 1 0:00 0.00% getty
Here we can see:
- The system has been up for more than a day.
- Load averages are very low (system is idle).
- CPU is mostly idle.
- Memory is mostly free.
- The
yes
command (a test program that just outputs "y" endlessly) is using almost all the CPU.
Quick check with uptime
If you don't need the full detail of top
, you can use:
% uptime
Which shows something like:
3:45PM up 2 days, 4:11, 2 users, load averages: 0.32, 0.28, 0.25
This tells you:
- Current time.
- How long the system has been running.
- How many users are logged in.
- Load averages (1, 5, 15 minutes).
Tip: Load averages are a quick way to see if your system is overloaded. On a single-CPU system, a load average of 1.00
means the CPU is fully busy. On a 4-core system, 4.00
means all cores are fully loaded.
Hands-On Lab: Watching the System
-
Run
uptime
and note your system's load averages. -
Open two terminals on your FreeBSD machine.
-
On the first terminal, start a busy process:
% yes > /dev/null &
-
On the second terminal run
top
to see how much CPU theyes
process is using. -
Stop the
yes
command withkill %1
orpkill yes
, or just by executing actrl+c
on the first terminal -
Run
uptime
again, notice how the load average is slightly higher than before, but it will drop back down over time.
Stopping Processes
Sometimes a process misbehaves or needs to be stopped. You can use:
-
kill - Send a signal to a process.
% kill 1055
(replace 1055 with the actual PID).
-
kill -9 - Force a process to terminate immediately.
% kill -9 1055
Use kill -9
only when necessary, because it doesn't give the program a chance to clean up.
When you use kill
, you're not literally "killing" a process with brute force; you're sending it a signal. Signals are messages the kernel delivers to processes.
- By default,
kill
sends SIGTERM (signal 15), which politely asks the process to terminate. Well-behaved programs clean up and exit. - If a process refuses, you can send SIGKILL (signal 9) with
kill -9 PID
. This forces the process to stop immediately, without cleanup. - Another useful one is SIGHUP (signal 1), often used to tell daemons (background services) to reload their configuration.
Try this:
% sleep 100 &
% ps aux | grep sleep
% kill -15 <PID> # try with SIGTERM first
% kill -9 <PID> # if still running, use SIGKILL
As a future driver developer, this distinction matters. Your code might need to handle termination gracefully, cleaning up resources instead of leaving the kernel in an unstable state.
Process Hierarchy: Parents and Children
Every process in FreeBSD (and in UNIX systems in general) has a parent process that started it. For example, when you type a command in the shell, the shell process is the parent, and the command you run becomes its child.
You can view this relationship using ps
with custom columns:
% ps -o pid,ppid,command | head -10
Example of the output (simplified):
PID PPID COMMAND
1 0 /sbin/init
534 1 /usr/sbin/cron
720 534 /bin/sh
721 720 sleep 100
Here you can see:
- Process 1 is
init
, the ancestor of all processes. cron
was started byinit
.- A
sh
shell process was started bycron
. - The
sleep 100
process was started by the shell.
Understanding process hierarchy matters when debugging: if a parent dies, its children may be adopted by init
. Later, when you work on drivers, you'll see how system daemons and services create and manage child processes that interact with your code.
Monitoring System Resources
FreeBSD provides simple commands to check system health:
-
df -h - Show disk usage.
% df -h
Example:
Filesystem Size Used Avail Capacity Mounted on /dev/ada0p2 50G 20G 28G 42% /
-
du -sh - Show size of a directory.
% du -sh /var/log
-
freebsd-version - Show OS version.
% freebsd-version
-
sysctl - Query system information.
% sysctl hw.model % sysctl hw.ncpu
Output might show your CPU model and number of cores.
Later, when writing drivers, you'll often use dmesg
and sysctl
to monitor how your driver interacts with the system.
Hands-On Lab: Working with Processes
Let's practice:
-
Run a sleep command in the background:
% sleep 30 &
-
Check running jobs:
% jobs
-
List processes:
% ps aux | grep sleep
-
Stop the process:
% kill <PID>
-
Run
top
and watch system activity. Pressq
to quit. -
Check system info:
% sysctl hw.model % sysctl hw.ncpu
Wrapping Up
In this section, you learned that processes are the living, running programs inside FreeBSD. You saw how to start them, move them between foreground and background, inspect them with ps
and top
, and stop them with kill
. You also explored basic system monitoring commands to check disk, CPU, and memory usage.
Processes are essential because they make the system alive, and as a driver developer, the programs that use your driver will always run as processes.
But monitoring processes is only part of the story. To do real work, you'll need more tools than those included in the base system. FreeBSD provides a clean and powerful way to install and manage extra software, from simple utilities like nano
to large applications like web servers. In the next section, we'll dive into the FreeBSD package system and the Ports Collection, so you can extend your system with the software you need.
3.7 Installing and Managing Software
FreeBSD is designed as a lean and reliable operating system. Out of the box, you get a rock-solid base system, the kernel, system libraries, essential tools, and configuration files. Everything beyond that, editors, compilers, servers, monitoring tools, and even desktop environments, is considered third-party software, and FreeBSD provides two excellent ways to install it:
- pkg - The binary package manager: fast, simple, and convenient.
- The Ports Collection - A massive source-based build system that allows fine-tuned customization.
Together, they give FreeBSD one of the most flexible and powerful software ecosystems in the UNIX world.
Binary Packages with pkg
The pkg
tool is FreeBSD's modern package manager. It gives you access to tens of thousands of prebuilt applications maintained by the FreeBSD ports team.
When you install a package with pkg
, here's what happens:
- The tool fetches a binary package from the FreeBSD mirrors.
- Dependencies are downloaded automatically.
- Files are installed under
/usr/local
. - The package database tracks what was installed, so you can update or remove it later.
Common Commands
-
Update the package repository:
% sudo pkg update
-
Search for software:
% sudo pkg search htop
-
Install software:
% sudo pkg install htop
-
Upgrade all packages:
% sudo pkg upgrade
-
Remove software:
% sudo pkg delete htop
For beginners, pkg
is the fastest and safest way to get software installed.
The FreeBSD Ports Collection
The Ports Collection is one of FreeBSD's crown jewels. It is a giant tree of build recipes (called "ports") located under /usr/ports
. Each port contains:
- A Makefile describing how to fetch, patch, configure, and build the software.
- Checksums for verifying integrity.
- Metadata about dependencies and licensing.
When you build software from ports, FreeBSD downloads the source code from the original project's site, applies FreeBSD-specific patches, and compiles it locally on your system.
Why Use Ports?
So why would anyone bother building from source when prebuilt packages are available?
- Customization - Many applications have optional features. With ports, you can choose exactly what to enable or disable during compilation.
- Optimization - Advanced users may want to compile with flags tuned for their hardware.
- Bleeding-edge options - Sometimes new features are available in ports before they make it into binary packages.
- Consistency with pkg - Ports and packages share the same underlying infrastructure. In fact, packages are built from ports by the FreeBSD build cluster.
Getting and Exploring the Ports Tree
The Ports Collection lives under /usr/ports
, but on a fresh FreeBSD system this directory may not exist yet. Let's check:
% ls /usr/ports
If you see categories such as archivers
, editors
, net
, security
, sysutils
, and www
, then Ports is installed. If the directory is missing, you'll need to fetch the Ports tree yourself.
Installing the Ports Collection with Git
The official and recommended way is to use Git:
-
Make sure
git
is installed:% sudo pkg install git
-
Clone the official Ports repository:
% sudo git clone https://git.FreeBSD.org/ports.git /usr/ports
This will create
/usr/ports
and fill it with the entire Ports Collection. The initial clone can take some time, since it contains thousands of applications. -
To update the ports tree later, just run:
% cd /usr/ports % sudo git pull
There is also an older tool called portsnap
, but Git is the modern, recommended method because it keeps your tree directly in sync with the FreeBSD project's repository.
Browsing the Ports
Once Ports is installed, explore it:
% cd /usr/ports
% ls
You'll see files and categories such as:
CHANGES UIDs comms ftp mail portuguese x11
CONTRIBUTING.md UPDATING converters games math print x11-clocks
COPYRIGHT accessibility databases german misc russian x11-drivers
GIDs arabic deskutils graphics multimedia science x11-fm
Keywords archivers devel hebrew net security x11-fonts
MOVED astro dns hungarian net-im shells x11-servers
Makefile audio editors irc net-mgmt sysutils x11-themes
Mk benchmarks emulators japanese net-p2p textproc x11-toolkits
README biology filesystems java news ukrainian x11-wm
Templates cad finance korean polish vietnamese
Tools chinese french lang ports-mgmt www
Each category has subdirectories for specific applications. For example:
% cd /usr/ports/sysutils/memdump
% ls
Here you'll find files like Makefile
, distinfo
, pkg-descr
and possibly a files/
directory. These are the "ingredients" FreeBSD uses to build the application: the Makefile
defines the process, distinfo
ensures integrity, pkg-descr
describes what this software does, and files/
contains any FreeBSD-specific patches.
Building from Ports
Example: installing memdump
from ports.
% cd /usr/ports/sysutils/memdump
% sudo make install clean
During the build, you may see a menu of options, such as enabling sensors or colours, installing documentation, etc. This is where ports shine, you control what features are compiled.
The make install clean
process does three things:
- install - builds and installs the program.
- clean - removes temporary build files.
Mixing Ports and Packages
A common question: Can I mix packages and ports?
Yes, they're compatible, since both are built from the same source tree. However, if you rebuild something from ports with custom options, you should be careful not to accidentally overwrite it with a binary package update later.
Many users install most things with pkg
, but use ports for specific applications where customization is important.
Where Installed Software Goes
Both pkg
and ports install third-party software under /usr/local
. This keeps them separate from the base system.
Typical locations:
- Binaries →
/usr/local/bin
- Libraries →
/usr/local/lib
- Configuration →
/usr/local/etc
- Man pages →
/usr/local/man
Try:
% which nano
Output:
/usr/local/bin/nano
This confirms that nano came from packages/ports, not from the base system.
Practical Example: Installing vim and htop
Let's try both methods.
Using pkg
% sudo pkg install vim htop
Run them:
% vim test.txt
% htop
Using Ports
% cd /usr/ports/sysutils/htop
% sudo make install clean
Run it:
% htop
Notice how the ports version may ask you about optional features during build, while pkg installs with defaults.
Hands-On Lab: Managing Software
-
Update your package repository:
% sudo pkg update
-
Install lynx with pkg:
% sudo pkg install lynx % lynx https://www.freebsd.org
-
Search for bsdinfo:
% pkg search bsdinfo
-
Install bsdinfo from ports:
% cd /usr/ports/sysutils/bsdinfo % sudo make install clean
-
Run bsdinfo to confirm it is now installed:
% bsdinfo
-
Remove nano:
% sudo pkg delete nano
You've now installed, run, and removed software with both pkg and ports, two complementary methods that give FreeBSD its flexibility.
Wrapping Up
In this section, you learned how FreeBSD handles third-party software:
- The pkg system gives you fast, easy binary installations.
- The Ports Collection offers source-based flexibility and customization.
- Both methods install under
/usr/local
, keeping the base system separate and clean.
Understanding this ecosystem is key to FreeBSD culture. Many administrators install common tools with pkg
and turn to ports when they need fine-grained control. As a developer, you'll appreciate both approaches: pkg for convenience, and ports when you want to see exactly how software is built and integrated.
But applications are only part of the story. The FreeBSD base system, the kernel and core utilities also need regular updates to stay secure and reliable. In the next section, we'll learn how to use freebsd-update
to keep the operating system itself current, so you always have a solid foundation to build on.
3.8 Keeping FreeBSD Up to Date
One of the most important habits you can develop as a FreeBSD user is keeping your system up to date. Updates fix security issues, squash bugs, and sometimes add support for new hardware. Unlike the command pkg update && pkg upgrade
, which update your applications, freebsd-update
command is used to update the base operating system itself, including the kernel and core utilities.
Keeping your system current ensures you're running FreeBSD safely and gives you the same solid foundation other developers are building on.
Why Updates Matter
- Security: Like any software, FreeBSD occasionally has security vulnerabilities. Updates patch these quickly.
- Stability: Bug fixes improve reliability, which is critical if you're developing drivers.
- Compatibility: Updates bring support for new CPUs, chipsets, and other hardware.
Don't think of updates as optional. They're part of responsible system administration.
The freebsd-update
Tool
FreeBSD makes updating simple with the freebsd-update
tool. It works by:
- Fetching information about available updates.
- Applying binary patches to your system.
- If needed, rebooting into the updated kernel.
This is much easier than rebuilding the system from source (which we'll learn later, when we need that level of control).
The Update Workflow
Here's the standard process:
-
Fetch available updates
% sudo freebsd-update fetch
This contacts the FreeBSD update servers and downloads any security patches or bug fixes for your version.
-
Review changes After fetching,
freebsd-update
may show you a list of configuration files that would be modified. Example:The following files will be updated as part of updating to 14.1-RELEASE-p3: /bin/ls /sbin/init /etc/rc.conf
Don't panic! This doesn't mean your system is broken, it just means some files will be updated.
- If system configuration files like
/etc/rc.conf
have changed in the base system, you'll be asked to review differences. freebsd-update
uses a merge tool to show side-by-side changes.- For beginners: if you're not sure, it's usually safe to accept the default (keep your local version). You can always read
/var/db/freebsd-update
logs later.
- If system configuration files like
Tip: If you're uncomfortable merging config files at this point, you can skip changes and check them manually later.
-
Install updates
% sudo freebsd-update install
This step applies the updates that were downloaded.
- If the update includes only userland programs (like
ls
,cp
, libraries), you're done. - If the update includes a kernel patch, you'll be asked to reboot after installation.
- If the update includes only userland programs (like
Example Session
Here's what a normal update might look like:
% sudo freebsd-update fetch
Looking up update.FreeBSD.org mirrors... 3 mirrors found.
Fetching metadata signature for 14.3-RELEASE from update1.FreeBSD.org... done.
Fetching metadata index... done.
Fetching 1 patches..... done.
Applying patches... done.
The following files will be updated as part of updating to 14.3-RELEASE-p1:
/bin/ls
/bin/ps
/sbin/init
% sudo freebsd-update install
Installing updates... done.
If the kernel was updated:
% sudo reboot
After reboot, your system is fully patched.
Kernel Updates with freebsd-update
One of the powerful things about freebsd-update
is that it can update the kernel itself. You don't have to rebuild it manually unless you want to run a custom kernel (we'll cover that later in the book).
This means that for most users, staying secure and current is just a matter of running fetch
+ install
regularly.
Upgrading to a New Release with freebsd-update
In addition to applying security and bug fix patches, freebsd-update
can also upgrade your system to a new FreeBSD release. For example, if you are running FreeBSD 14.2 and want to upgrade to 14.3, the process is straightforward.
The workflow has three steps:
-
Fetch upgrade files
% sudo freebsd-update upgrade -r 14.3-RELEASE
Replace
14.3-RELEASE
with the release you want to upgrade to. -
Install the new components
% sudo freebsd-update install
This installs the first stage of updates. If the kernel was updated, you will need to reboot:
% sudo reboot
-
Repeat install After reboot, run the install step again to finish updating the rest of the system:
% sudo freebsd-update install
At the end, you'll be running the new release. You can confirm with:
% freebsd-version
Tip: Release upgrades can sometimes involve configuration file merges (just like security updates). If in doubt, keep your local versions, you can always compare with the new defaults stored under /var/db/freebsd-update/
.
And remember, it's also a good idea to update your packages after a release upgrade, since they are built against the new system libraries:
% sudo pkg update
% sudo pkg upgrade
Hands-On Lab: Running Your First Update
-
Check your current FreeBSD version:
% freebsd-version -kru
-k
→ kernel-r
→ running-u
→ userland
-
Run
freebsd-update fetch
to see if updates are available. -
Carefully read any messages about configuration file merges. If unsure, choose to keep your version.
-
Run
freebsd-update install
to apply updates. -
If the kernel was updated, reboot:
% sudo reboot
Common Beginner Pitfall: Fear of Config File Merges
When freebsd-update
asks you to merge changes, it can look intimidating, with lots of text, plus/minus symbols, and prompts. Don't worry.
- If in doubt, keep your local version of files like
/etc/rc.conf
or/etc/hosts
. - The system will still work.
- You can always inspect the new default files later (they're stored in
/var/db/freebsd-update/
).
With time, you'll get comfortable resolving these merges, but in the beginning, choosing to keep your configuration is the safe route.
Wrapping Up
With just two commands, freebsd-update fetch
and freebsd-update install
, you now know how to keep your FreeBSD base system patched and secure. This process takes only a few minutes but ensures your environment is safe and reliable for development work.
Later, when we begin working on the kernel and writing drivers, we'll also learn how to build and install a custom kernel from source. But for now, you already have the essential knowledge to maintain your system like a pro.
And since checking for updates is something you may want to do regularly, wouldn't it be nice if the system could take care of some of these chores for you automatically? That's exactly what we'll look at next: scheduling and automation with tools like cron
, at
, and periodic
.
3.9 Scheduling and Automation
One of UNIX's greatest strengths is that it was designed to let the computer handle repetitive tasks for you. Instead of waiting until midnight to run a backup or logging in every morning to start a monitoring script, you can tell FreeBSD:
"Run this command for me at this time, every day, forever."
This not only saves time but also makes your system more reliable. In FreeBSD, the main tools for this are:
- cron - for recurring tasks, like backups or monitoring.
- at - for one-time jobs you want to schedule later.
- periodic - FreeBSD's built-in system for routine maintenance tasks.
Why Automate Tasks?
Automation matters because enhance our:
- Consistency - A job scheduled with cron will always run, even if you forget.
- Efficiency - Instead of manually repeating commands, you write them once.
- Reliability - Automation helps avoid mistakes. Computers don't forget to rotate logs on Sunday night.
- System maintenance - FreeBSD itself relies heavily on cron and periodic to keep the system healthy (rotate logs, update databases, run security checks).
cron: The Automation Workhorse
The cron
daemon runs continuously in the background. Every minute, it checks a list of scheduled jobs (stored in crontabs) and runs those that match the current time.
Each user has their own crontab, and the system has a global one. This means you can schedule personal tasks (like cleaning files in your home directory) without touching system jobs.
Understanding the crontab Format
The crontab format has five fields that describe when to run a job, followed by the command itself:
minute hour day month weekday command
- minute: 0–59
- hour: 0–23 (24-hour clock)
- day: 1–31
- month: 1–12
- weekday: 0–6 (0 = Sunday, 6 = Saturday)
A mnemonic to help you remember: "My Hungry Dog Must Wait." (Minute, Hour, Day, Month, Weekday)
Examples of cron jobs
-
Run every day at midnight:
0 0 * * * /usr/bin/date >> /home/dev/midnight.log
-
Run every 15 minutes:
*/15 * * * * /home/dev/scripts/check_disk.sh
-
Run every Monday at 8 AM:
0 8 * * 1 echo "Weekly meeting" >> /home/dev/reminder.txt
-
Run at 3:30 AM on the first of every month:
30 3 1 * * /usr/local/bin/backup.sh
Editing and Managing Crontabs
To edit your personal crontab:
crontab -e
This opens your crontab in the default editor (vi
or ee
).
To list your jobs:
crontab -l
To remove your crontab:
crontab -r
Where Do Logs Go?
When cron runs a job, its output (stdout and stderr) is sent by email to the user who owns the job. On FreeBSD, these emails are delivered locally and stored in /var/mail/username
.
You can also redirect output to a log file to make things easier:
0 0 * * * /home/dev/backup.sh >> /home/dev/backup.log 2>&1
Here:
>>
appends output tobackup.log
.2>&1
redirects error messages (stderr) into the same file.
This way, you always know what your cron jobs did, even if you don't check system mail.
at: One-Time Scheduling
Sometimes you don't want a recurring job, you just want something to run later, once. That's where at comes in.
The usage is pretty simple, let's see some examples:
- Run a command 10 minutes from now:
echo "echo Hello FreeBSD > /home/dev/hello.txt" | at now + 10 minutes
-
Run a command tomorrow at 9 AM:
echo "/usr/local/bin/htop" | at 9am tomorrow
Jobs scheduled with at
are queued and run exactly once. You can list them with atq
and remove them with atrm
.
periodic: FreeBSD's Maintenance Helper
FreeBSD comes with a built-in housekeeping system called periodic. It's a framework of shell scripts that handle routine maintenance tasks for you, so you don't have to remember them manually.
These tasks run automatically at daily, weekly, and monthly intervals, thanks to entries already configured in the system-wide cron file /etc/crontab
. This means a freshly installed FreeBSD system already takes care of many chores without you lifting a finger.
Where the Scripts Live
The scripts are organized in directories under /etc/periodic
:
/etc/periodic/daily
/etc/periodic/weekly
/etc/periodic/monthly
/etc/periodic/security
- daily/ - jobs that run every day (log rotation, security checks, database updates).
- weekly/ - jobs that run once a week (like updating the locate database).
- monthly/ - jobs that run once a month (like monthly accounting reports).
- security/ - additional checks focused on system security.
What periodic Does by Default
Some examples of the jobs included out of the box:
- Security checks - looks for setuid binaries, insecure file permissions, or known vulnerabilities.
- Log rotation - compresses and archives logs under
/var/log
so they don't grow forever. - Database updates - rebuilds helper databases, like the one used by the
locate
command. - Temporary file cleanup - removes leftovers in
/tmp
and other cache directories.
After they run, periodic scripts usually send a summary of their results to the root user's mailbox (read it by running mail
as root).
Common Beginner Pitfall: "Nothing Happened!"
Many new FreeBSD users run their system for a few days, knowing periodic is supposed to run jobs daily, but they never see any output and assume it didn't work. In reality, periodic's reports are sent to the root user's mail, not displayed on screen.
To read them, log in as root and run:
# mail
Press Enter to open the mailbox and view the reports. You can quit the mail program by typing q
.
Tip: If you prefer to receive these reports in your normal user's inbox, you can configure mail forwarding in /etc/aliases
so that root's mail is redirected to your user account.
Running periodic Manually
You don't have to wait for cron to trigger them. You can run the full sets of jobs manually:
% sudo periodic daily
% sudo periodic weekly
% sudo periodic monthly
Or run just one script directly, for example:
% sudo /etc/periodic/security/100.chksetuid
Customizing periodic with periodic.conf
Periodic is not a black box. Its behavior is controlled through /etc/periodic.conf
and /etc/periodic.conf.local
.
Best practice: never edit the scripts themselves. Instead, override their behavior in periodic.conf
, this keeps your changes safe when FreeBSD updates the base system.
Here are some common options you might use:
-
Enable or disable jobs
daily_status_security_enable="YES" daily_status_network_enable="NO"
-
Control log handling
daily_clean_hoststat_enable="YES" weekly_clean_pkg_enable="YES"
-
Enable locate database update
weekly_locate_enable="YES"
-
Control tmp cleanup
daily_clean_tmps_enable="YES" daily_clean_tmps_days="3"
-
Security reports
daily_status_security_inline="YES" daily_status_security_output="mail"
To see all available options, use the command man periodic.conf
Discovering All Available Checks
By now you know periodic runs daily, weekly, and monthly jobs, but you may wonder: what exactly are all these checks, and what do they do?
There are several ways to explore them:
-
List the scripts directly
% ls /etc/periodic/daily % ls /etc/periodic/weekly % ls /etc/periodic/monthly % ls /etc/periodic/security
You'll see files with names like
100.clean-disks
or480.leapfile-ntpd
, the script names are descriptive and will give you an idea about what the script does. The numbers help control the order in which they run. -
Read the documentation
The man pages
periodic(8)
andperiodic.conf(5)
explain many of the available scripts and their options. For example:man periodic.conf
Gives you a summary of configuration variables and what they control.
-
Check the script headers Open any script in
/etc/periodic/*/
withless
and read the first few comment lines. They usually contain a human-readable explanation of the script's purpose.
This means you never have to guess what periodic is doing; you can always inspect the scripts, preview their behaviour, or read the official documentation.
Why This Matters for Developers
For everyday users, periodic keeps the system tidy and secure without extra effort. But as a developer, you may later want to:
- Add a custom periodic script to test your driver or monitor its health once a day.
- Rotate or clean up custom log files created by your driver.
- Run automated integrity checks (e.g., verify your driver's device node exists and responds).
By hooking into periodic, you leverage the same framework FreeBSD itself uses for its own housekeeping.
Hands-On Lab: Exploring and Customizing periodic
-
List the available daily scripts:
% ls /etc/periodic/daily
-
Run them manually:
% sudo periodic daily
-
Open
/etc/periodic.conf
(create it if it doesn't exist) and add:weekly_locate_enable="YES"
-
Preview what the weekly jobs will do:
% sudo periodic weekly
-
Trigger the weekly jobs and then try:
% locate passwd
Hands-On Lab: Automating Tasks
- Schedule a job to run every minute for testing:
% crontab -e
*/1 * * * * echo "Hello from cron: $(date)" >> /home/dev/cron_test.log
-
Wait a few minutes and check the file:
% tail -n 5 /home/dev/cron_test.log
-
Schedule a one-time job with
at
:% echo "date >> /home/dev/at_test.log" | at now + 2 minutes
Check later:
% cat /home/dev/at_test.log
-
Run a periodic task manually:
% sudo periodic daily
You'll see reports on log files, security, and system status.
Common Pitfalls for Beginners
- Forgetting to set full paths. Cron jobs don't use the same environment as your shell, so always use full paths (
/usr/bin/ls
instead of justls
). - Forgetting to redirect output. If you don't, results may be mailed to you silently.
- Overlapping jobs. Be careful not to schedule jobs that conflict or run too frequently.
Why This Matters for Driver Developers
You might wonder why we're spending time on cron jobs and scheduled tasks. The answer is that automation is a developer's best friend. When you begin writing device drivers, you'll often want to:
- Schedule automatic tests of your driver (for example, checking whether it loads and unloads cleanly every night).
- Rotate and archive kernel logs to keep track of driver behavior over time.
- Run periodic diagnostics that interact with your driver's
/dev
node and record results for analysis.
By mastering cron and periodic now, you'll already know how to set up these background routines later, saving yourself time and catching bugs early.
Wrapping Up
In this section, you learned how FreeBSD automates tasks using three main tools:
- cron for recurring jobs,
- at for one-time scheduling,
- periodic for built-in system maintenance.
You practiced creating jobs, checked their output, and learned how FreeBSD itself relies on automation to stay healthy.
Automation is powerful, but sometimes you need to go beyond fixed schedules. You might want to chain commands together, use loops, or add logic to decide what happens. That's where shell scripting comes in. In the next section, we'll write your first scripts and see how to create custom automation tailored to your needs.
3.10 Introduction to Shell Scripting
You have learned to run commands one by one. Shell scripting lets you save those commands into a reusable program. On FreeBSD, the native and recommended shell for scripting is /bin/sh
. This shell follows the POSIX standard and is available on every FreeBSD system.
Important note for Linux users On many Linux distributions, examples use bash. On FreeBSD, bash is not part of the base system. You can install it with
pkg install bash
, where it will live under/usr/local/bin/bash
. For portable, dependency-free scripts on FreeBSD, use#!/bin/sh
.
We will build this section progressively: shebang and execution, variables and quoting, conditions, loops, functions, working with files, return codes, and basic debugging. Every example script below is fully commented so a complete beginner can follow it.
1) Your first script: shebang, make it executable, run it
Create a file named hello.sh
:
#!/bin/sh
# hello.sh a first shell script using FreeBSD's native /bin/sh
# Print a friendly message with the current date and the active user.
# 'date' prints the current date and time
# 'whoami' prints the current user
echo "Hello from FreeBSD!"
echo "Date: $(date)"
echo "User: $(whoami)"
Tip: What Does #!
(Shebang) Mean?
The first line of this script is:
#!/bin/sh
This is called the shebang line. The two characters #!
tell the system which program should interpret the script.
#!/bin/sh
means: "run this script using the sh shell."- On other systems you might also see
#!/bin/tcsh
,#!/usr/bin/env python3
, or#!/usr/bin/env bash
.
When you make a script executable and run it, the system looks at this line to decide which interpreter to use. Without it, the script may fail or behave differently depending on your login shell.
Rule of thumb: Always include a shebang line at the top of your scripts. On FreeBSD, #!/bin/sh
is the safest and most portable choice.
Now let's make the script executable and run it:
% chmod +x hello.sh # give the user execute permission
% ./hello.sh # run it from the current directory
If you get "Permission denied", you forgot chmod +x
.
If you get "Command not found", you probably typed hello.sh
without ./
and the current directory is not included in system PATH
.
Tip: Don't feel pressured to master all scripting features at once. Start small, write a 2–3 line script that prints your username and the date. Once you're comfortable, add conditions (if
), then loops, then functions. Shell scripting is like LEGO: build one block at a time.
2) Variables and quoting
Shell variables are untyped strings. Assign with name=value
and reference with $name
. There must be no spaces around =
.
#!/bin/sh
# vars.sh demonstrate variables and proper quoting
name="dev"
greeting="Welcome"
# Double quotes preserve spaces and expand variables.
echo "$greeting, $name"
# Single quotes prevent expansion. This prints the literal characters.
echo '$greeting, $name'
# Command substitution captures output of a command.
today="$(date +%Y-%m-%d)"
echo "Today is $today"
Common beginner pitfalls:
- Using spaces around
=
:name = dev
is an error. - Forgetting quotes when variables may contain spaces. Use
"${var}"
as a habit.
3) Exit status and short circuit operators
Every command returns an exit status. Zero means success. Nonzero means error. The shell lets you chain commands using &&
and ||
.
#!/bin/sh
# status.sh show exit codes and conditional chaining
# Try to list a directory that exists. 'ls' should return 0.
ls /etc && echo "Listing /etc succeeded"
# Try something that fails. 'false' always returns nonzero.
false || echo "Previous command failed, so this message appears"
# You can test the last status explicitly using $?
echo "Last status was $?"
4) Tests and conditions: if
, [ ]
, files and numbers
Use if
with the test
command or its bracket form [ ... ]
. There must be spaces inside the brackets.
#!/bin/sh
# ifs.sh demonstrate file and numeric tests
file="/etc/rc.conf"
# -f tests if a regular file exists
if [ -f "$file" ]; then
echo "$file exists"
else
echo "$file does not exist"
fi
num=5
if [ "$num" -gt 3 ]; then
echo "$num is greater than 3"
fi
# String tests
user="$(whoami)"
if [ "$user" = "root" ]; then
echo "You are root"
else
echo "You are $user"
fi
Useful file tests:
-e
exists-f
regular file-d
directory-r
readable-w
writable-x
executable
Numeric comparisons:
-eq
equal-ne
not equal-gt
greater than-ge
greater or equal-lt
less than-le
less or equal
5) Loops: for
and while
Loops let you repeat work over files or lines of input.
#!/bin/sh
# loops.sh for and while loops in /bin/sh
# A 'for' loop over pathnames. Always quote expansions to handle spaces safely.
for f in /etc/*.conf; do
echo "Found conf file: $f"
done
# A 'while' loop to read lines from a file safely.
# The 'IFS=' and 'read -r' avoid trimming spaces and backslash escapes.
count=0
while IFS= read -r line; do
count=$((count + 1))
done < /etc/hosts
echo "The /etc/hosts file has $count lines"
Arithmetic in POSIX sh uses $(( ... ))
for simple integer math.
6) Case statements for tidy branching
case
is great when you have several patterns to match.
#!/bin/sh
# case.sh handle options with a case statement
action="$1" # first command line argument
case "$action" in
start)
echo "Starting service"
;;
stop)
echo "Stopping service"
;;
restart)
echo "Restarting service"
;;
*)
echo "Usage: $0 {start|stop|restart}" >&2
exit 2
;;
esac
7) Functions to organize your script
Functions keep code readable and reusable.
#!/bin/sh
# functions.sh - Demonstrates using functions and command-line arguments in a shell script.
#
# Usage:
# ./functions.sh NUM1 NUM2
# Example:
# ./functions.sh 5 7
# This will output: "[INFO] 5 + 7 = 12"
# A simple function to print informational messages
say() {
# "$1" represents the first argument passed to the function
echo "[INFO] $1"
}
# A function to sum two integers
sum() {
# "$1" and "$2" are the first and second arguments
local a="$1"
local b="$2"
# Perform arithmetic expansion to add them
echo $((a + b))
}
# --- Main script execution starts here ---
# Make sure the user provided two arguments
if [ $# -ne 2 ]; then
echo "Usage: $0 NUM1 NUM2"
exit 1
fi
say "Beginning work"
# Call the sum() function with the provided arguments
result="$(sum "$1" "$2")"
# Print the result in a nice format
say "$1 + $2 = $result"
8) A practical example: a tiny backup script
This script creates a timestamped archive of a directory into ~/backups
. It uses only base utilities available on FreeBSD Base System.
#!/bin/sh
# backup.sh create a timestamped tar archive of a directory
# Usage: ./backup.sh /path/to/source
# Notes:
# - Uses /bin/sh so it runs on a clean FreeBSD 14.x install.
# - Creates ~/backups if it does not exist.
# - Names the archive sourcebasename-YYYYMMDD-HHMMSS.tar.gz
set -eu
# set -e: exit immediately if any command fails
# set -u: treat use of unset variables as an error
# Validate input
if [ $# -ne 1 ]; then
echo "Usage: $0 /path/to/source" >&2
exit 2
fi
src="$1"
# Verify that source is a directory
if [ ! -d "$src" ]; then
echo "Error: $src is not a directory" >&2
exit 3
fi
# Prepare destination directory
dest="${HOME}/backups"
mkdir -p "$dest"
# Build a safe archive name using only the last path component
base="$(basename "$src")"
stamp="$(date +%Y%m%d-%H%M%S)"
archive="${dest}/${base}-${stamp}.tar.gz"
# Create the archive
# tar(1) is in the base system. The flags mean:
# - c: create - z: gzip - f: file name - C: change to directory
tar -czf "$archive" -C "$(dirname "$src")" "$base"
echo "Backup created: $archive"
Run it:
% chmod +x backup.sh
% ./backup.sh ~/directory_you_want_to_backup
You will find the archive under ~/backups
.
9) Working with temporary files safely
Never hardcode names like /tmp/tmpfile
. Use mktemp(1)
from the base system.
#!/bin/sh
# tmp_demo.sh create and clean a temporary file safely
set -eu
tmpfile="$(mktemp -t myscript)"
# Arrange cleanup on exit for success or error
cleanup() {
[ -f "$tmpfile" ] && rm -f "$tmpfile"
}
trap cleanup EXIT
echo "Temporary file is $tmpfile"
echo "Hello temp" > "$tmpfile"
echo "Contents: $(cat "$tmpfile")"
trap
schedules a function to run when the script exits, which prevents stale files.
10) Debugging your scripts
set -x
prints each command before executing it. Add it near the top and remove once fixed.echo
progress messages so the user knows what is happening.- Check return codes and handle failures explicitly.
- Log to a file by redirecting output:
mycmd >> ~/my.log 2>&1
.
Example:
#!/bin/sh
# debug_demo.sh show simple tracing
# set -x comment to disable verbose trace:
set -x
echo "Step 1"
ls /etc >/dev/null
echo "Step 2"
date
11) Putting it together: organize downloads by type
This small utility sorts files in ~/Downloads
into subfolders by extension. It demonstrates loops, case, tests and safety checks.
#!/bin/sh
# organize_downloads.sh - Tidy ~/Downloads by file extension
#
# Usage:
# ./organize_downloads.sh
#
# Creates subdirectories like Documents, Images, Audio, Video, Archives, Other
# and moves matched files into them safely.
set -eu
downloads="${HOME}/Downloads"
# Ensure the Downloads directory exists
if [ ! -d "$downloads" ]; then
echo "Downloads directory not found at $downloads" >&2
exit 1
fi
cd "$downloads"
# Create target folders if missing
mkdir -p Documents Images Audio Video Archives Other
# Use find to safely list all regular (non-hidden) files
# -print0 ensures null-delimited results, safe for strange filenames
count=0
find . -maxdepth 1 -type f ! -name ".*" -print0 |
while IFS= read -r -d '' f; do
# Strip leading "./" from path
fname=${f#./}
# Convert filename extension to lowercase for matching
lower=$(printf '%s' "$fname" | tr '[:upper:]' '[:lower:]')
case "$lower" in
*.pdf|*.txt|*.md|*.doc|*.docx) dest="Documents" ;;
*.png|*.jpg|*.jpeg|*.gif|*.bmp) dest="Images" ;;
*.mp3|*.wav|*.flac) dest="Audio" ;;
*.mp4|*.mkv|*.mov|*.avi) dest="Video" ;;
*.zip|*.tar|*.gz|*.tgz|*.bz2) dest="Archives" ;;
*) dest="Other" ;;
esac
echo "Moving '$fname' -> $dest/"
mv -n -- "$fname" "$dest/" # -n prevents overwriting existing files
count=$((count + 1))
done
if [ $count -eq 0 ]; then
echo "No files to organize."
else
echo "Done. Organized $count file(s)."
fi
Hands-on Lab: three mini tasks
- Write a logger
Create
logger.sh
that appends a timestamped line to~/activity.log
with the current directory and user. Run it, then view the log withtail
. - Check disk space
Create
check_disk.sh
that warns when root filesystem usage exceeds 80 percent. Usedf -h /
and parse the percentage with${var%%%}
style trimming or a simpleawk
. Exit with status 1 if above the threshold so cron can alert you. - Wrap your backup
Create
backup_cron.sh
that callsbackup.sh
from earlier and logs output to~/backup.log
. Add a crontab entry to run it daily at 3 AM. Remember to use full paths inside the script.
All scripts should start with #!/bin/sh
, contain comments explaining each step, use quotes around variable expansions, and handle errors where sensible.
Common beginner pitfalls and how to avoid them
- Using bash features in
#!/bin/sh
scripts. Stick to POSIX constructs. If you require bash, say so in the shebang and remember it is under/usr/local/bin/bash
on FreeBSD. - Forgetting to quote variables. Use
"${var}"
to prevent word splitting and globbing surprises. - Assuming the same environment under cron. Always use full paths and redirect output to a log file.
- Hardcoding temporary file names. Use
mktemp
andtrap
to clean up. - Spaces around
=
in assignments.name=value
is correct.name = value
is not.
Wrapping up
In this section you learned the native FreeBSD way to automate work with portable scripts that run on any clean FreeBSD install. You can now write small programs with /bin/sh
, handle arguments, test conditions, loop through files, define functions, use temporary files safely, and debug issues with simple tools. In your driver journey, scripts will help you repeat tests, gather logs, and package builds reliably.
But remember: you don't need to memorize every construct or command option. Part of being productive in UNIX is knowing where to find the right information at the right time. Every developer, from beginner to expert, constantly looks up man pages, handbooks, and online resources.
That's exactly what we'll cover next. In the following section, you'll learn how to use FreeBSD's built-in documentation, the famous FreeBSD Handbook, and the community around the project. These resources will become your companions as you continue your journey into device driver development.
3.11 Seeking Help and Documentation in FreeBSD
No one, not even the most experienced developer, remembers every command, option, or system call. The real strength of a UNIX system like FreeBSD is that it ships with excellent documentation and has a supportive community that can help when you get stuck.
In this section, we'll explore the main ways to get information: man pages, the FreeBSD Handbook, online resources, and the community. By the end, you'll know exactly where to look when you have a question, whether it's about using ls
or writing a device driver.
The Power of man Pages
The manual pages, or man pages, are the built-in reference system for UNIX. Every command, system call, library function, configuration file, and kernel interface has a man page.
You read them with the man
command, for example:
% man ls
This opens the documentation for ls
, the command to list directory contents. Use the spacebar to scroll, q
to quit.
Man Page Sections
FreeBSD organizes man pages into numbered sections. The same name may exist in multiple sections, so you specify which one you want.
- 1 - User commands (e.g.,
ls
,cp
,ps
) - 2 - System calls (e.g.,
open(2)
,write(2)
) - 3 - Library functions (C standard library, math functions)
- 4 - Device drivers and special files (e.g.,
null(4)
,random(4)
) - 5 - File formats and conventions (
passwd(5)
,rc.conf(5)
) - 7 - Miscellaneous (protocols, conventions)
- 8 - System administration commands (e.g.,
ifconfig(8)
,shutdown(8)
) - 9 - Kernel developer interfaces (critical for driver writers!)
Example:
% man 2 open # system call open()
% man 9 bus_space # kernel function for accessing device registers
Man Section 9: The Kernel Developer's Manual
Most FreeBSD users live in section 1 (user commands) and administrators spend a lot of time in section 8 (system management). But as a driver developer, you'll spend much of your time in section 9.
Section 9 contains the kernel developer interfaces documentation for functions, macros, and subsystems that are only available inside the kernel.
Some examples:
man 9 device
- Overview of device driver interfaces.man 9 bus_space
- Accessing hardware registers.man 9 mutex
- Synchronization primitives for the kernel.man 9 taskqueue
- Scheduling deferred work in the kernel.man 9 malloc
- Memory allocation inside the kernel.
Unlike section 2 (system calls) or section 3 (libraries), these are not available in user space. They are part of the kernel itself, and you'll use them when writing drivers and kernel modules.
Think of section 9 as the developer's API manual for the FreeBSD kernel.
Hands-On Preview
You don't need to understand all the details yet, but you can take a peek:
% man 9 device
% man 9 bus_dma
% man 9 sysctl
You'll see that the style is different from user command man pages: these are focused on kernel functions, structures, and usage examples.
Later in this book, we'll constantly refer to section 9 as we introduce new kernel features. Consider it your most important companion for the road ahead.
Searching the man Pages
If you don't know the exact command name, use the -k
flag (equivalent to apropos
):
man -k network
This shows every man page related to networking.
Another example:
man -k disk | less
This will show you tools, drivers, and system calls related to disks.
The FreeBSD Handbook
The FreeBSD Handbook is the official, comprehensive guide to the operating system.
You can read it online:
https://docs.freebsd.org/en/books/handbook/
The Handbook covers:
- Installing FreeBSD
- System administration
- Networking
- Storage and filesystems
- Security and jails
- Advanced topics
The Handbook is an excellent complement to this book. While we focus on device driver development, the Handbook gives you broad system knowledge that you can always come back to.
Other Documentation
- Online man pages: https://man.freebsd.org
- FreeBSD Wiki: https://wiki.freebsd.org (community-maintained notes, HOWTOs, and work-in-progress documentation).
- Developer's Handbook: https://docs.freebsd.org/en/books/developers-handbook is aimed at programmers.
- Porter's Handbook: https://docs.freebsd.org/en/books/porters-handbook if you package software for FreeBSD.
Community and Support
Documentation will get you far, but sometimes you need to talk to real people. FreeBSD has an active and welcoming community.
- Mailing lists: https://lists.freebsd.org
freebsd-questions@
is for general user help.freebsd-hackers@
is for development discussions.freebsd-drivers@
is specific to device driver development.
- FreeBSD Forums: https://forums.freebsd.org a friendly and beginner-friendly place to ask questions.
- User Groups:
- Around the world, there are FreeBSD and BSD user groups that organize meetups, talks, and workshops.
- Examples include NYCBUG (New York City BSD User Group), BAFUG (Bay Area FreeBSD User Group), and many university-based clubs.
- You can usually find them via the FreeBSD Wiki, local tech mailing lists, or meetup.com.
- If you don't find one nearby, consider starting a small group, even a handful of enthusiasts meeting online or in person can become a valuable support network.
- Chat:
- IRC on Libera.Chat (
#freebsd
). - Discord communities exist and are pretty active, use this link to join: https://discord.com/invite/freebsd
- IRC on Libera.Chat (
- Reddit: https://reddit.com/r/freebsd
User groups and forums are especially valuable because you can often ask questions in your native language, or even meet people who are contributing to FreeBSD in your area.
How to Ask for Help
At some point, everyone gets stuck. One of FreeBSD's strengths is its active and supportive community, but to get useful answers, you need to ask clear, complete, and respectful questions.
When you post to a mailing list, forum, IRC, or Discord channel, include:
-
Your FreeBSD version Run:
% uname -a
This tells helpers exactly which release, patch level, and architecture you are using.
-
What you were trying to do Describe your goal, not just the command that failed. Helpers can sometimes suggest a better approach than the one you attempted.
-
The exact error messages Copy and paste the error text instead of paraphrasing it. Even small differences matter.
-
Steps to reproduce the problem If someone else can repeat your issue, they can often solve it much faster.
-
What you already tried Mention commands, configuration changes, or documentation you consulted. This shows you've made an effort and prevents people from suggesting things you already did.
Example of a Poor Help Request
"Ports aren't working, how do I fix it?"
This leaves out version, commands, errors, and context. Nobody can answer without guessing.
Example of a Good Help Request
"I'm running FreeBSD 14.3-RELEASE on amd64. I tried building
htop
from ports withcd /usr/ports/sysutils/htop && make install clean
. The build failed with the error:error: ncurses.h: No such file or directory
I already tried
pkg install ncurses
, but the error remains. What should I check next?"
This is short but complete; version, command, error, and troubleshooting steps are all there.
Tip: Always stay polite and patient. Remember, most FreeBSD contributors are volunteers. A clear, respectful question not only increases your chances of a helpful reply, but also builds goodwill in the community.
Hands-On Lab: Exploring Documentation
-
Open the man page for
ls
. Find and try at least two options you didn't know.% man ls
-
Use
man -k
to search for commands related to disks.% man -k disk | less
-
Open the man page for
open(2)
and compare it toopen(3)
. What's the difference? -
Peek into the kernel developer documentation:
% man 9 device
-
Visit https://docs.freebsd.org/ and find the page on system startup (
rc.d
). Compare it toman rc.conf
.
Wrapping Up
FreeBSD gives you powerful tools to teach yourself. The man pages are your first stop; they're always on your system, always up to date, and cover everything from basic commands to kernel APIs. The Handbook is your big-picture guide, and the community mailing lists, forums, user groups, and online chat are there to help when you need human answers.
Later, as you write drivers, you'll rely heavily on man pages (especially section 9) and on discussions in FreeBSD mailing lists and forums. Knowing how to find information is just as important as memorizing commands.
Next, we will look inside the system to peek at kernel messages and tunables. Tools like dmesg
and sysctl
let you see what the kernel is doing and will become essential when you start loading and testing your own device drivers.
3.12 Peeking into the Kernel and System State
At this point, you know how to move around in FreeBSD, manage files, control processes, and even write scripts. That makes you a capable user. But writing drivers means stepping into the mind of the kernel. You'll need to see what FreeBSD itself sees:
- What hardware was detected?
- Which drivers were loaded?
- What tunable knobs exist inside the kernel?
- How do devices appear to the operating system?
FreeBSD gives you three magical windows into the kernel's state:
dmesg
- the kernel's diary.sysctl
- the control panel full of switches and meters./dev
- the doorway where devices show up as files.
These three tools will become your companions. Every time you add or debug a driver, you'll use them. Let's explore them now, step by step.
dmesg: Reading the Kernel's Diary
Imagine FreeBSD as a pilot starting an airplane. As the system boots, the kernel checks its hardware: CPUs, memory, disks, USB devices and each driver reports back. Those messages are not lost; they're stored in a buffer you can read at any time with:
% dmesg | less
You'll see lines like:
Copyright (c) 1992-2023 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 14.3-RELEASE releng/14.3-n271432-8c9ce319fef7 GENERIC amd64
FreeBSD clang version 19.1.7 (https://github.com/llvm/llvm-project.git llvmorg-19.1.7-0-gcd708029e0b2)
VT(vga): text 80x25
CPU: AMD Ryzen 7 5800U with Radeon Graphics (1896.45-MHz K8-class CPU)
Origin="AuthenticAMD" Id=0xa50f00 Family=0x19 Model=0x50 Stepping=0
Features=0x1783fbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,MMX,FXSR,SSE,SSE2,HTT>
Features2=0xfff83203<SSE3,PCLMULQDQ,SSSE3,FMA,CX16,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,TSCDLT,AESNI,XSAVE,OSXSAVE,AVX,F16C,RDRAND,HV>
AMD Features=0x2e500800<SYSCALL,NX,MMX+,FFXSR,Page1GB,RDTSCP,LM>
AMD Features2=0x8003f7<LAHF,CMP,SVM,CR8,ABM,SSE4A,MAS,Prefetch,OSVW,PCXC>
Structured Extended Features=0x219c07ab<FSGSBASE,TSCADJ,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA>
Structured Extended Features2=0x40061c<UMIP,PKU,OSPKE,VAES,VPCLMULQDQ,RDPID>
Structured Extended Features3=0xac000010<FSRM,IBPB,STIBP,ARCH_CAP,SSBD>
XSAVE Features=0xf<XSAVEOPT,XSAVEC,XINUSE,XSAVES>
IA32_ARCH_CAPS=0xc000069<RDCL_NO,SKIP_L1DFL_VME,MDS_NO>
AMD Extended Feature Extensions ID EBX=0x1302d205<CLZERO,XSaveErPtr,WBNOINVD,IBPB,IBRS,STIBP,STIBP_ALWAYSON,SSBD,VIRT_SSBD,PSFD>
SVM: NP,NRIP,VClean,AFlush,NAsids=16
...
...
This is the kernel telling you:
- what hardware it found,
- which driver claimed it,
- and sometimes, what went wrong.
Later in this book, when you load your own driver, dmesg
is where you'll look for your first "Hello, kernel!" message.
The output of dmesg
can be very long, you can use grep
to filter and see only what you need, for example:
% dmesg | grep ada
This will show only messages about disk devices (ada0
, ada1
).
sysctl: The Kernel's Control Panel
If dmesg
is the diary, sysctl
is the dashboard full of knobs and meters. It exposes thousands of kernel variables at runtime: some read-only (system info), others tunable (system behavior).
Try this commands:
% sysctl kern.ostype
% sysctl kern.osrelease
% sysctl hw.model
% sysctl hw.ncpu
Output might look like:
kern.ostype: FreeBSD
kern.osrelease: 14.3-RELEASE
hw.model: AMD Ryzen 7 5800U with Radeon Graphics
hw.ncpu: 8
Here you just asked the kernel:
- What OS am I running?
- What version?
- What CPU?
- How many cores?
Exploring Everything
To see all parameters that you can finetune with sysctl
, you can run the command below:
% sysctl -a | less
This prints the entire control panel thousands of values. They are organized by categories:
kern.*
- kernel properties and settings.hw.*
- hardware information.net.*
- network stack details.vfs.*
- filesystem settings.debug.*
- debugging variables (often useful for developers).
It's overwhelming at first, but don't worry, you'll learn to fish out what matters.
Changing Values
Some sysctls are writable. For example:
% sudo sysctl kern.hostname=myfreebsd
% hostname
You've just changed your hostname at runtime.
Important: Changes made this way disappear after reboot unless saved in /etc/sysctl.conf
.
/dev: Where Devices Come to Life
Now for the most exciting part.
FreeBSD represents devices as special files inside /dev
. This is one of UNIX's most elegant ideas:
If everything is a file, then everything can be accessed in a consistent way.
Run:
% ls -d /dev/* | less
You'll see a sea of names:
/dev/null
- the "black hole" where data goes to disappear./dev/zero
- an infinite stream of zeros./dev/random
- cryptographically secure random numbers./dev/tty
- your terminal./dev/ada0
- your SATA disk./dev/da0
- a USB disk.
Try interacting:
echo "Testing" > /dev/null # silently discards output
head -c 16 /dev/zero | hexdump # shows zeros in hex
head -c 16 /dev/random | hexdump # random bytes from the kernel
Later, when you create your first driver, it will show up here as a file named /dev/hello
. Reading or writing to that file will trigger your kernel code. This is the moment when you'll feel the bridge between userland and the kernel.
Hands-On Lab: Your First Peek Inside
-
View all kernel messages:
% dmesg | less
-
Find your storage devices:
% dmesg | grep ada
-
Ask the kernel about your CPU:
% sysctl hw.model % sysctl hw.ncpu
-
Change your hostname temporarily:
% sudo sysctl kern.hostname=mytesthost % hostname
-
Interact with special device files:
% echo "Hello FreeBSD" > /dev/null % head -c 8 /dev/zero | hexdump % head -c 8 /dev/random | hexdump
With this short lab, you've already read kernel messages, queried kernel variables, and touched device nodes, exactly what professional developers do daily.
From Shell to Hardware: The Big Picture
To understand why tools like dmesg
, sysctl
, and /dev
are so powerful, it helps to picture how FreeBSD is layered:
+----------------+
| User Space | ← Commands you run: ls, ps, pkg, scripts
+----------------+
↓
+----------------+
| Shell (sh) | ← Interprets your commands into syscalls
+----------------+
↓
+----------------+
| Kernel | ← Handles processes, memory, devices, filesystems
+----------------+
↓
+----------------+
| Hardware | ← CPU, RAM, disks, USB, network cards
+----------------+
Whenever you type a command in the shell, it travels down this stack:
- The shell interprets it.
- The kernel executes it by managing processes, memory, and devices.
- The hardware responds.
Then the results bubble back up for you to see.
Understanding this flow is essential for driver developers: when you interact with /dev
, you're connecting directly to the kernel, which in turn talks to the hardware.
Common Beginner Pitfalls
Exploring the kernel can be exciting, but here are some common mistakes to watch out for:
-
Confusing
dmesg
with system logsdmesg
only shows the kernel's ring buffer, not all logs.- Old messages may disappear after new ones push them out.
- For complete logs, check
/var/log/messages
.
-
Forgetting that
sysctl
changes don't persist-
If you change a setting with
sysctl
, it resets at reboot. -
To make it permanent, add it to
/etc/sysctl.conf
. -
Example:
% echo 'kern.hostname="myhost"' | sudo tee -a /etc/sysctl.conf
-
-
Overwriting files in
/dev
/dev
entries aren't normal files; they're live connections to the kernel.- Redirecting output to them can have real effects.
- Writing to
/dev/null
is safe, but writing random data to/dev/ada0
(your disk) could destroy it. - Rule of thumb: explore
/dev/null
,/dev/zero
,/dev/random
, and/dev/tty
, but leave storage devices (ada0
,da0
) alone unless you know exactly what you're doing.
-
Expecting
/dev
entries to stay the same- Devices appear and disappear as hardware is added or removed.
- For example, plugging in a USB stick may create
/dev/da0
. - Don't hardcode device names into scripts without verifying.
-
Not using full paths in automation
- Cron and other automated tools may not have the same
PATH
as your shell. - Always use full paths (
/sbin/sysctl
,/bin/echo
) when scripting kernel interactions.
- Cron and other automated tools may not have the same
Wrapping Up
In this section, you opened three magical windows into FreeBSD's kernel:
dmesg
- the diary of the system, recording hardware detection and driver messages.sysctl
- the control panel that reveals (and sometimes adjusts) kernel settings./dev
- the place where devices come to life as files.
The big picture to remember is this: whenever you type a command, it travels through the shell, down into the kernel, and finally to the hardware. The results then bubble back up for you to see. Tools like dmesg
, sysctl
, and /dev
let you peek into that flow and see what the kernel is doing behind the scenes.
These aren't just abstract tools; they're exactly how you'll see your own driver appear in the system. When you load your module, you'll watch dmesg
light up, you may expose a knob with sysctl
, and you'll interact with your device node under /dev
.
Before we move on to the next chapter and start learning about C programming, let's pause to consolidate everything you've learned in this chapter. In the next section, we'll review the key ideas and give you a set of challenges to practice, exercises that will help lock in these new skills and prepare you for the journey ahead.
3.13 Putting It All Together: Your FreeBSD Journey So Far
Congratulations! You've just taken your first deep dive into UNIX and FreeBSD. What started as abstract ideas is now becoming practical skills. You can move around the system, manage files, edit and install software, control processes, automate tasks, and even peek into the kernel's inner workings.
Let's take a moment to review what you've accomplished in this chapter:
- What UNIX is and why it matters - A philosophy of simplicity, modularity, and "everything is a file," inherited by FreeBSD.
- The Shell - Your window into the system, where commands follow the consistent structure of
command [options] [arguments]
. - Filesystem Layout - A single hierarchy starting at
/
, with special roles for directories like/etc
,/usr/local
,/var
, and/dev
. - Users, Groups, and Permissions - The foundation of FreeBSD's security model, controlling who can read, write, or execute.
- Processes - Programs in motion, with tools like
ps
,top
, andkill
to manage them. - Installing Software - Using
pkg
for quick binary installs, and the Ports Collection for source-based flexibility. - Automation - Scheduling tasks with
cron
, one-time jobs withat
, and maintenance withperiodic
. - Shell Scripting - Turning repetitive commands into reusable programs using FreeBSD's native
/bin/sh
. - Peeking into the Kernel - Using
dmesg
,sysctl
, and/dev
to observe the system at a deeper level.
That's a lot, but don't worry if you don't feel like an expert yet. The goal of this chapter was not perfection, but comfort: comfort in the shell, comfort in exploring FreeBSD, and comfort in seeing how UNIX works under the hood. That comfort will carry forward as we begin writing real code for the system.
Practice Ground
To make sure these skills stick, here are 46 exercises.
They're grouped by topic, so you can practice section by section or mix them up as you like.
Filesystem and Navigation (8 exercises)
- Use
pwd
to confirm your current directory, then move into/etc
and back into your home directory usingcd
. - Create a directory
unix_playground
in your home. Inside it, create three subdirectories:docs
,code
, andtmp
. - Inside
unix_playground/docs
, create a file calledreadme.txt
with the text "Welcome to FreeBSD". Useecho
and output redirection. - Copy
readme.txt
into thetmp
directory. Verify both files exist withls -l
. - Rename the file in
tmp
tocopy.txt
. Then delete it withrm
. - Use
find
to locate every.conf
file inside/etc
. - Use absolute paths to copy
/etc/hosts
into yourdocs
directory. Then use relative paths to move it intotmp
. - Use
ls -lh
to display file sizes in human-readable format. Which file in/etc
is the largest?
Users, Groups, and Permissions (6 exercises)
- Create a file called
secret.txt
in your home directory. Make it readable only by you. - Create a directory
shared
and give read/write access to everyone (mode 777). Test it by writing a file into it. - Use
id
to list your user's UID, GID, and groups. - Use
ls -l
on/etc/passwd
and/etc/master.passwd
. Compare their permissions and explain why they differ. - Create a file and change its owner to
root
usingsudo chown
. Try editing it as a normal user. What happens? - Add a new user with
sudo adduser
. Set a password, log in as that user, and check their default home directory.
Processes and System Monitoring (7 exercises)
- Start a process in the foreground with
sleep 60
. While it runs, open another terminal and useps
to find it. - Start the same process in the background with
sleep 60 &
. Usejobs
andfg
to bring it back to the foreground. - Use
top
to find which process is consuming the most CPU at the moment. - Start a
yes
process (yes > /dev/null &
) to flood the CPU. Watch it intop
, then stop it withkill
. - Check how long your system has been running with
uptime
. - Use
df -h
to see how much disk space is available on your system. Which filesystem is mounted on/
? - Run
sysctl vm.stats.vm.v_page_count
to see the number of memory pages on your system.
Installing and Managing Software (pkg and Ports) (6 exercises)
- Use
pkg search
to look for a text editor other thannano
. Install it, run it, then remove it. - Install the
htop
package withpkg
. Compare its output to the built-intop
. - Explore the Ports Collection by navigating to
/usr/ports/editors/nano
. Look at the Makefile. - Build
nano
from ports withsudo make install clean
. Did it ask you about options? - Update your ports tree using
git
. Which categories were updated? - Use
which
to locate where the binary ofnano
orhtop
was installed. Check whether it's under/usr/bin
or/usr/local/bin
.
Automation and Scheduling (cron, at, periodic) (6 exercises)
- Write a cron job that logs the current date and time every 2 minutes into
~/time.log
. Wait and check it withtail
. - Write a cron job that cleans up all
.tmp
files in your home directory every night at midnight. - Use the
at
command to schedule a message to yourself 5 minutes from now. - Run
sudo periodic daily
and read its output. What kinds of tasks does it perform? - Add a cron job that runs
df -h
every day at 8 AM and logs the result to~/disk.log
. - Redirect cron job output into a custom log file (
~/cron_output.log
). Confirm that both normal output and errors are captured.
Shell Scripting (/bin/sh) (7 exercises)
- Write a script
hello_user.sh
that prints your username, current date, and number of processes running. Make it executable and run it. - Write a script
organize.sh
that moves all.txt
files from your home directory into a folder calledtexts
. Add comments to explain each step. - Modify
organize.sh
to also create subdirectories by file type (images
,docs
,archives
). - Write a script
disk_alert.sh
that warns you if root filesystem usage exceeds 80%. - Write a script
logger.sh
that appends a timestamped entry to~/activity.log
with the current directory and user. - Write a script
backup.sh
that creates a.tar.gz
archive of~/unix_playground
into~/backups/
. - Extend
backup.sh
so that it keeps only the last 5 backups and deletes older ones automatically.
Peeking into the Kernel (dmesg, sysctl, /dev) (6 exercises)
- Use
dmesg
to find the model of your primary disk. - Use
sysctl hw.model
to display your CPU model andsysctl hw.ncpu
to display how many cores you have. - Change your hostname temporarily using
sysctl kern.hostname=mytesthost
. Check it withhostname
. - Use
ls /dev
to list device nodes. Identify which ones represent disks, terminals, and virtual devices. - Use
head -c 16 /dev/random | hexdump
to read 16 random bytes from the kernel. - Plug in a USB stick (if available) and run
dmesg | tail
. Can you see which new/dev/
entry appeared?
Wrapping Up
With these 46 exercises, you've covered every major topic in this chapter:
- Filesystem navigation and layout
- Users, groups, and permissions
- Processes and monitoring
- Software installation with pkg and ports
- Automation with cron, at, and periodic
- Shell scripting with FreeBSD's native
/bin/sh
- Kernel introspection with dmesg, sysctl, and /dev
By completing them, you'll move from being a passive reader to an active UNIX practitioner. You'll not only know how FreeBSD works, you'll have lived inside it.
These exercises are the muscle memory you'll need when we start programming. When we dive into C and later kernel development, you'll already be fluent in the daily tools of a UNIX developer.
Looking Ahead
The next chapter will introduce the C programming language, the language of the FreeBSD kernel. This is the tool you'll use to create device drivers. Don't worry if you've never programmed before, we'll build your understanding step by step, just as we did with UNIX in this chapter.
By combining your new UNIX literacy with C programming skills, you'll be ready to begin shaping the FreeBSD kernel itself.