FreeBSD Basics

The System Startup Daemon: init


Previously in this series:

Discovering System Processes

Discovering System Processes Part II

In the last few articles, we've learned how to view and manage running processes. Today, I'd like to take a look at how all those processes actually get started.

A lot of neat stuff happens when you boot up your computer into FreeBSD. I won't cover all the details here, as the FreeBSD handbook does an excellent job of explaining the bootup process. When you boot your computer, you have probably noticed that the kernel does a hardware probe and prints its results to your terminal. Once this probe is finished, the kernel starts two processes: process 0 (swapper) and process 1 (init).

The daemon responsible for process control initialization is init; without it, no other processes would be able to start. At boot time, init has two important jobs to do: First, it launches the startup scripts controlled by rc, then it initializes the terminals so they will be available for logins by users. Let's pick apart these functions, starting with rc:
whatis rc
rc(8)     - command scripts for auto-reboot and daemon startup

These scripts actually live in /etc/rc; normally, the configuration files found in /etc have a corresponding entry in section 5 of the manual so you can find out how to correctly make changes to the configuration file. However, if you type:

man 5 rc

you'll receive this message:

No entry for rc in section 5 of the manual

It seems a bit odd that a configuration file would be in section 8 of the manual, as this section contains system maintenance and operation commands, which are usually daemons. Let's take a closer look at this file to see what is going on here:

more /etc/rc
# System startup script run by init on autoboot
# or after single-user.
# Output and error are redirected to console by init,
# and the console is the controlling terminal.
# Note that almost all of the user-configurable behavior 
# is no longer in # this file, but rather in /etc/defaults/rc.conf.
# Please check that file first before contemplating any changes 
# here.  If you do need to change this file for some reason, we 
# would like to know about it.

OK, that's pretty clear; looks like we're not supposed to muck about with this file ourselves. There must be some pretty important stuff in here necessary for the proper bootup of our system. Let's skip through the file and look at some of its highlights to find out what actually is happening during this portion of startup. Note that init is recording all output and error messages to the terminal when the rc script is actually processed during bootup. (I'll tab in my comments; lines starting at the left are from the file /etc/rc)

One of the first things rc does is set a path variable so it can find the executables on your FreeBSD system:

It then looks for the /etc/defaults/rc.conf and /etc/rc.conf files:

# If there is a global system configuration file, suck it in.
if [ -f /etc/defaults/rc.conf ]; then
        . /etc/defaults/rc.conf
elif [ -f /etc/rc.conf ]; then
        . /etc/rc.conf

It then does a file system consistency check. If you've ever improperly shut down your FreeBSD system, you'll notice that it will complain at this point in the bootup process.

echo Automatic boot in progress...
fsck -p

Assuming that fsck did not encounter any problems, it will now mount your filesystems:

# Mount everything except nfs filesystems.
mount -a -t nonfs

Before any other daemons can be started, your CMOS clock must be adjusted so it will be understood by the kernel clock:

adjkerntz -i

The var directory is then cleaned up, and the boot messages are written to dmesg.boot:

clean_var() {
	if [ ! -f /var/run/clean_var ]; then
		rm -rf /var/run/*
		find /var/spool/lock ! -type d -delete
		rm -rf /var/spool/uucp/.Temp/*
		# Keep a copy of the boot messages around
		dmesg >/var/run/dmesg.boot

Then rc will read the following files:


Then it will reset the terminal permissions:

# Whack the pty perms back into shape.
chflags 0 /dev/tty[pqrsPQRS]*
chmod 666 /dev/tty[pqrsPQRS]*
chown root:wheel /dev/tty[pqrsPQRS]*

and clean up its mess and clear /tmp:

# Clean up left-over files
# Clearing /tmp at boot-time seems to have a long tradition.  It doesn't
# help in any way for long-living systems, and it might accidentally
# clobber files you would rather like to have preserved after a crash
# (if not using mfs /tmp anyway).
# See also the example of another cleanup policy in /etc/periodic/daily.
# Remove X lock files, since they will prevent you from restarting X11
# after a system crash.

Now rc is ready to start up some daemons, starting with syslogd and named:

# Start system logging and name service.  Named needs to start before syslogd
# if you don't have a /etc/resolv.conf.

then inetd, cron, lpd, sendmail, sshd, and usbd:

# Now start up miscellaneous daemons that don't belong anywhere else

Then rc will update motd (message of the day) and print out "uname -m," which displays your type of architecture to the screen.

(end of /etc/rc)

Once we've reached the end of /etc/rc, rc's job is finished. Let's recap what happened here: init called the rc script which read several global and local configuration files in order to properly mount the filesystems and create an environment where the system daemons could be started. Your operating system is now up and running, but at this point, there is no environment where a user can actually interact with that operating system. This is where init's second important function kicks in.

The configuration file /etc/ttys will be read to determine which terminals need to be initialized. Unlike /etc/rc, this file is often edited by the superuser to ensure that the desired terminals will be initialized by init.

In order to understand this file, we must realize that there are three types of terminals on your FreeBSD system. Virtual terminals start with "ttyv" followed by a number or letter; these are the terminals available for users physically seated at the FreeBSD computer. By default, the first of these virtual terminals, or "ttyv0," represents the console. Serial or dial-up terminals start with "ttyd" followed by a number; these terminals are available for users accessing your FreeBSD system remotely, using a modem. The last type of terminal is a pseudo or network terminal; these start with "ttyp" followed by a number or a letter and are used to access your FreeBSD computer over a network connection.

If we look at this file using

more /etc/ttys

we'll see that this file has been divided into three sections, with a section for each of the three types of terminals. Each section also has four columns, which I've summarized in the following chart:

Column Name

What it Represents


The name of the terminal device.


The program to start running on the terminal, which is typically getty. Other common entries include xdm, which starts the X Window System, or none, meaning no program.


For virtual consoles, the correct type is cons25. Other common values include network on pseudo-terminals, dialup for incoming modem ports, and unknown when the terminal type a user will try to connect with cannot be predetermined.


Must be on or off. If on, init will run the program specified in the getty column. If the word "secure" appears, this tty allows root login; to prevent root logins, use the word "insecure."

Let's start deciphering this file by looking at the virtual terminal section; note that it starts by setting up the console:

# If console is marked "insecure", then init will ask 
# for the root password when going to single-user mode.
console	none				unknown	off secure

If the fsck command runs into problems during bootup, init will put your FreeBSD system into single-user mode so the root user can fix the problem. If you set the console at insecure instead of the default secure, init will require the root password before you can continue.

ttyv0	"/usr/libexec/getty Pc"		cons25	on  secure
# Virtual terminals
ttyv1	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv2	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv3	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv4	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv5	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv6	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv7	"/usr/libexec/getty Pc"		cons25	on  secure
ttyv8	"/usr/X11R6/bin/xdm -nodaemon"	xterm	off secure

You'll note that on my FreeBSD system I have eight virtual terminals in addition to the console; I can access each by pressing ALT and one of the function keys. For example, ALT F1 accesses the console, ALT F2 accesses ttyv1, ALT F3 accesses ttyv2, etc. If I start an X session, it can be accessed by using ALT F8. If I were to change the word off to on at ttyv8, I would receive an X terminal instead of the console at boot time. I could still use my ALT function keys to access the other terminals. All of my virtual terminals are marked as "secure," meaning they will accept root logins. How many virtual terminals you have depends on your version of FreeBSD; if you wish to create more virtual terminals, you should read What is a virtual console and how do I make more?.

Now let's move on down to the dial-up terminals:

# Serial terminals
# The 'dialup' keyword identifies dialin lines to login, fingerd etc.
ttyd0	"/usr/libexec/getty std.9600"	dialup	off secure
ttyd1	"/usr/libexec/getty std.9600"	dialup	off secure
ttyd2	"/usr/libexec/getty std.9600"	dialup	off secure
ttyd3	"/usr/libexec/getty std.9600"	dialup	off secure
You'll notice that I have four available dial-up terminals, but they are all turned off. If I wanted users to access my FreeBSD computer using a modem, I'd have to turn at least one of these terminals on. I would also have to decide if I wanted these users to be able to log in as root; if not, I would change the word secure to insecure. You'll note that the getty column includes the number 9600, which represents a data transfer rate of 9600 bps. Since most modern modems are capable of higher rates, I would also probably change that number to 57600. And finally, I would read the section of the FreeBSD handbook that covers the dial-in service.

The last section in /etc/ttys is the network or pseudo terminal section. You'll note that there are a lot of these, 255 to be precise, that range from:

# Pseudo terminals
ttyp0   none         network


ttySv   none         network

and that none of them have been enabled by default.

If you ever become the superuser in order to make changes to /etc/ttys, you will have to remember to send a HUP signal to init so that it will use your changes. To do this, type:

kill -1 1

as -1 is signal 1 (HUP) and 1 is process 1 (init).

Now, what is this getty program that keeps being mentioned in /etc/ttys? The description in man 8 getty states it well:


The getty program is called by init(8) to open and initialize the tty line, read a login name, and invoke login(1).

So, init reads /etc/ttys and starts a getty process on every terminal you've told it to in that configuration file. Monitoring that terminal to see if anyone tries to log in is getty's job. If someone does, getty will start the login program to verify that user's login name and password. If those check out, login will start up that user's login shell and place the user in their home directory. Once the user has a shell, or command interpreter, they now have a way of interacting with the operating system. It is now up to the shell to interpret a user's input and ensure that any necessary processes are started.

When a user logs out of their login shell, init is called in to start another getty process which will patiently monitor the terminal for another login attempt.

Let's tie together this whole process by looking at the output of the ps command on a freshly booted, default install of FreeBSD 4.1. I'll use the -ax switches to include the system daemons:

ps -ax
    0  ??  DLs    0:00.01  (swapper)
    1  ??  ILs    0:00.16 /sbin/init --
    2  ??  DL     0:00.02  (pagedaemon)
    3  ??  DL     0:00.00  (vmdaemon)
    4  ??  DL     0:00.02  (bufdaemon)
    5  ??  DL     0:01.02  (syncer)
 1056  ??  Is     0:00.00 adjkerntz -i
 1187  ??  Ss     0:00.08 syslogd -s
 1206  ??  Is     0:00.05 inetd -wW
 1208  ??  Is     0:00.11 cron
 1622  ??  Ss     0:00.02 sendmail: accepting connections on port 25 (sendmail)
 1621  v0  Ss     0:00.12 -csh (csh)
 1701  v0  R+     0:00.00 ps -ax
 1699  v1  Is+    0:00.01 /usr/libexec/getty Pc ttyv1
 1619  v2  Is+    0:00.01 /usr/libexec/getty Pc ttyv2
 1618  v3  Is+    0:00.01 /usr/libexec/getty Pc ttyv3
 1617  v4  Is+    0:00.01 /usr/libexec/getty Pc ttyv4
 1616  v5  Is+    0:00.01 /usr/libexec/getty Pc ttyv5
 1615  v6  Is+    0:00.01 /usr/libexec/getty Pc ttyv6
 1614  v7  Is+    0:00.01 /usr/libexec/getty Pc ttyv7

You should now be able to recognize most of these processes: swapper has a PID of 0 and init has a PID of 1. The adjkerntz, syslogd, inetd, cron, and sendmail processes were all successfully started by rc. I needed to run the ps command from a shell; in my case, it was from the c shell running on ttyv0. Getty processes are waiting for logins on virtual terminals 1-7. There is no getty process running on virtual terminal 8 as this terminal was marked "off" in /etc/ttys.

We've gone pretty deep into FreeBSD in this last set of articles. Next week, let's take a break from the heavy stuff and play with another utility from the ports collection.

Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.

Read more FreeBSD Basics columns.

Discuss this article in the Operating Systems Forum.

Return to the BSD DevCenter.


Copyright © 2017 O'Reilly Media, Inc.