Roland's FreeBSD page

Documentation and setup tips

My picture.

Location: homepage > FreeBSD


Valid XHTML 1.0! Valid
          CSS!

Introduction

This page is a gathering place for all my FreeBSD related stuff, except my software.

Apart from the normal text, there are different colors used for

/path/of/file
configuration files

and

shell commands.

If a shell command is preceded by a dollar sign ($), it should be run by a normal user. Commands preceded by a hash mark (#) should be run as the root user.

Topics covered on this page:

Documentation

When I was setting up my Athlon64 box with FreeBSD 5.3, I had some trouble figuring out how to retain device permissions across reboots. That's why I wrote manual pages for devfs.conf(5) and devfs.rules(5). These are included in current releases.

Installation

Before actually installing FreeBSD on my new amd64 box, I ran 5.3 inside qemu on my old Slackware box. This allowed me to practice things before doing the real install. At a minimum, I'd recommend keeping an old computer with an internet connection handy when installing.

Since my system has enough disk space, I did a complete installation. For partitioning, I didn't follow the system recommendation, but used a separate partition for /home.

One thing I will change if I re-install FreeBSD is the location of /usr/local. For easier dumps, I'd place it on a separate partition, since this is where most ports install their stuff.

My install went without problems. Before buying my new system, I had selected components that were supported by FreeBSD. A bit of reading through motherboard docs online goes a long way here. I cannot stress enough how important this is. A bit of work here can save you a world of grief afterwards. The thing to watch is de make and type of the chips on the motherboard and cards you want to buy, NOT the brand name of the card/mobo. This is especially true for WiFi cards, as these may be sold with different chipsets without changing the name or model number!

System configuration

After installing the base system, I made some changes so that the system suits me better. I'm documenting them here in the hope that they will be usefull for others. These settings were made for FreeBSD 5.3 on amd64, but have been continuously updated to 7-STABLE.

To keep track of things, I keep configuration files (including the kernel configuration) under revision control with git. My reason for using git is that I use it for all my projects, including these webpages. Unlike traditional revision control systems, git handles binary files (e.g. pictures) well. It is also very fast. For text files like configuration files you could also use rcs or cvs.

The reason for doing this is that it makes it easier to spot and undo mistakes that can disrupt your system. Before I install a modified version of a configuration file, I commit the changes to the revision control system. If this change ends up breaking part of the system, it is easy to spot the change and restore a previous (working) version of the file in question.

I use a couple of perl scripts to check for differences between files in my configuration directory and the real files in the system directories, and to install newer files if possible. Both files use a list of files to compare, en excerpt of which follows:

filelist.root excerpt
# setup file            perm    system file             commands
boot/device.hints       644     /boot/device.hints              
boot/loader.conf        644     /boot/loader.conf
etc/X11/xorg.conf       644     /etc/X11/xorg.conf
etc/aspell.conf         644     /usr/local/etc/aspell.conf
etc/cdrecord            644     /usr/local/etc/cdrecord
etc/csh.cshrc           644     /etc/csh.cshrc
etc/devfs.conf          644     /etc/devfs.conf
etc/devfs.rules         644     /etc/devfs.rules
etc/esd.conf            644     /usr/local/etc/esd.conf
etc/fbtab               644     /etc/fbtab
etc/fstab               644     /etc/fstab
etc/group               644     /etc/group
...

Lines starting with a '#' are ignored. Other lines contain a file in the setup tree, a permission of the system file, the location of the system file and optional commands to be executed after the file is installed.

The script check.pl uses md5 sums to compare files in the setup directory with their associated file in the system configuration. If they don't match it prints the unified diff between them.

check.pl
#!/usr/bin/perl
# Check for changes in config files.
$name = `id -u -n`;
open(RF, "filelist.$name") || die "Cannot open list file 'filelist.$name'.";
while(<RF>) {
    chomp;
    if (/^#/) {next}; # skip comment lines.
    ($src,$perm,$dest) = split;
    if (-r $dest) {
	$msrc = `md5 -q $src`;
	$mdest = `md5 -q $dest`;
	if ($msrc ne $mdest) {
	    printf "%s != %s\n", $src, $dest; 
	    system "diff", "-u", $dest, $src;
	} else {
	    #printf "%s matches %s\n", $src, $dest;
	}
    } else {
	printf "%s cannot be read.\n", $dest;
    }
}
close(RF);

Using the same file description list, the script install.pl installs files that have changed in the setup directory or that are absent in the filesystem:

install.pl
#!/usr/bin/perl
# Install files according to instructions in 'filelist.$USER'.
# Time-stamp: <2008-12-27 21:59:54 rsmith>
$name = `id -u -n`;
open(RF, "filelist.$name") || die "Cannot open list file 'filelist.$name'.";
while(<RF>) {
    chomp;
    if (/^#/) {next}; # Skip comment lines.
    @cmds = split;
    $src = shift @cmds;
    $perm = shift @cmds; 
    $dest = shift @cmds;
    # Skip identical files.
    if (-e $dest) {
        $msrc = `md5 -q $src`;
        $mdest = `md5 -q $dest`;
        if ($msrc eq $mdest) {next};
    }
    # Create directories if necessary
    $tdir = `dirname $dest`;
    chomp $tdir;
    if (! -d $tdir) {
	print "\e[31m";
	$rv = system "install", "-d", $tdir;
	$rv>>8;
	if ($rv == 0) {
	    printf "\e[32mCreated %s.\n\e[39m", $tdir;
	} else {print "\e[39m";}
    }
    # Install the file
    print "\e[31m";
    $rv = system "install", "-p", "-m", $perm, $src, $dest;
    $rv>>8;
    if ($rv == 0) {
	printf "\e[32mInstalled %s as %s.\n\e[39m", $src, $dest;
	# Execute post-install commands.
	if (@cmds) {
	    $rv = system @cmds;
	    $rv>>8;
	    if ($rv != 0) {
		printf "\e[31mPost-install commands for %s failed.\n\e[39m", 
		$src;
	    }
	}
    } else {print "\e[39";}
}
close(RF);

Parallel port

My Laserjet 2550 printer attached to the parallel port printed very slowly. The system logfile mentioned that the system was throttling interrupts from the parallel port because of an "interrupt storm". After reading the ppc(4) manual page, I added the following to /boot/device.hints, to put the port into polling mode:

hint.ppc.0.flags="0x28"

The flag 0x08 puts the port into ECP mode, and 0x20 makes the driver poll the port, instead of using an interrupt.

When using CUPS like I am, its programs need to have access to the printer device. In my case connected to the parallel port;

# chown root:cups /dev/lpt0
# chmod g+rw /dev/lpt0

To make this change permanent, you can add the following rules to /etc/devfs.conf;

# Give cups printer access
own     lpt0    root:cups
perm    lpt0    0660

This will make sure that the relevant group and permissions will be installed after the next reboot.

In case you have a USB connected printer, you should add a rule to devfs.rules for a ulpt(4) device.

The printer now works fine with CUPS. One caveat I came across, is that you need to use the command-line tools to install a printer with a PPD file. I used the following command to install my printer in CUPS:

# /usr/local/sbin/lpadmin -E -p clj2550 -v parallel:/dev/lpt0 -P clj2550.ppd

Sound

My computer has an Asus P5KPL-VM motherboard, which has AC97 compatible onboard sound. To enable that, I added the following devices to my kernel configuration file:

# Soundcard support
device          sound
device          snd_hda

While playing music with xmms(1), I noticed little clicks and lags in the sound output. After some googling I added the following line to /boot/device.hints, to enlarge the DMA buffer for the sound driver (the default is 4096 bytes).

hint.pcm.0.buffersize="16384"

The sound driver is able to combine sounds from different sources and output then through one device. This is activated in sysctl.conf.

This was sufficient to fix the problem.

Ethernet/ADSL

My ADSL connection goes through a Thompson Speedtouch 510 ADSL ethernet modem/router. This makes the setup very easy, because to the computer it's just another IP gateway to the internet. So it's compatible with almost all operating systems. If you want easy setup, go for one of these.

My aforementioned motherboard has a Attansic/Atheros L1 ethernet chip on-board. I also have an extra PCI ethernet card, an old 3Com Fast Etherlink XL. To enable these, I added the following to my kernel configuration file:

# PCI ethernet device
device          miibus
device          xl              # 3Com Fast Etherlink XL
device          age             # Attansic/Atheros L1 Gigabit Ethernet

Initially, I used a card with a realtek 8139 chip to connect a laptop for transferring files, but that didn't work very well. Transferring files from the laptop to the desktop could saturate the link, but transfer from the desktop to the laptop was extremely slow, topping out at an intermittant rate of 200 kB/s. Switching to an old 3Com card I had improved this enormously. This can saturate the link in both directions.

The following settings were added to /etc/rc.conf to enable these devices:

# Network settings
ifconfig_lo0="inet 127.0.0.1"
ifconfig_age0="inet 10.0.0.150/24 polling media 100baseTX mediaopt full-duplex"
ifconfig_xl0="inet 192.168.0.1/24 polling media 100baseTX mediaopt full-duplex"
defaultrouter="10.0.0.138"
tcp_extensions="NO"

The defaultrouter entry points to my ADSL modem. The IP address for the sk0 interface can be freely chosen from the 10.0.0.x address range. This Just Works™.

Devfs

FreeBSD 5.x has a dynamic /dev filesystem. This means that entries in /dev are created or removed depending on the available devices.

When devices are created, they get default ownership and permission settings. These settings can be changed via the devfs(8) program, or with the chown(1) and chmod(8) utilities. The problem is that settings made in this manner do not survive a reboot, and settings made with chmod and chown do not survive a device being unplugged.

Enter the files /etc/devfs.conf and /etc/devfs.rules. The first one is suited for changing those devices that are available at boot time, and are not likely to be unplugged, like CD-ROM drives etc. The second one is best suited for setting permissions etc. for devices that can be plugged in and removed during normal system operation, e.g. USB devices,

What I wanted to do is give groups of users access to the CD-ROM, floppy and USB devices, without giving everybody access and thereby compromising system security. So I created three groups (with the pw(8) utility); usb, floppy and cdrom, and made the users that were authorized to use these devices members of these groups.

CD-ROM/RW

Since I wanted to use cdrecord(1), I had to set up the CD drive commands to go through the CAM interface. To do this, the following devices were set in the kernel configuration:

device          atapicam        # Emulate ATAPI devices as SCSI via CAM
                                # Requires scbus and pass

device          scbus           # SCSI bus (required for SCSI)
device          cd              # Compact Disc
device          da              # Direct Access (disks)
device          pass            # Passthrough device

(The da device is added because it is used for USB mass storage devices, as we'll see later.)

After the new kernel is installed, and the system is rebooted, there will be a couple of new devices ; cdN instead of acdN (N is a number), passN and xpt0. The cdrecord program needs access to those devices to function.

To do that, the following lines are added to /etc/devfs.conf:

/etc/devfs.conf
# /etc/devfs.conf
# Time-stamp: <2006-12-02 09:09:45 rsmith>
# This is for devices present at boot. See devfs.rules for devices created
# at runtime.

# Give members of group cdrom access to the CD/DVD-ROM and DVD+RW via the
# SCSI interface
own     xpt0    root:cdrom
perm    xpt0    0660
own     cd0     root:cdrom
perm    cd0     0660
link    cd0     cdrom
link    cd0     dvd
own     cd1     root:cdrom
perm    cd1     0660

# Access to the floppy disk.
own     fd0     root:floppy
perm    fd0     0660

# Give cups printer access
own     lpt0    root:cups
perm    lpt0    0660

What these commands essentially do is give members of the group cdrom read and write access to the devices necessary to let cdrecord function for a non-root user.

By default, ATAPI devices like CD-ROMs do not use DMA. You can enable DMA at runtime with the atacontrol(8) command. First, run atacontrol list (as root) to see on which channel your ATAPI device is. Say that it's the master on channel 1. Then the next step is to see it's current mode by running atacontrol mode 1. Next you can change the mode by running atacontrol mode 1 UDMA2 XXX. This should set the device to UDMA2, aka UDMA33. See the atacontrol manual page for a list of valid modes. You must specify modes for both master and slave, but XXX is an invalid mode and will be ignored.

To enable DMA for ATAPI devices at boot, add the following to /boot/loader.conf:

hw.ata.atapi_dma="1"

Devfs configuration for hotpluggable devices

To set permissions etc. for the USB devices that might not be plugged in at boot, we use /etc/devfs.rules. The rules set in this files are processed by the /etc/rc.d/devfs script which uses devfs(8) to put the rules in the devfs system.

I've got a couple of USB mass storage devices that can be accessed via the da(4) driver, and a USB scanner that works with the uscanner(4) driver.

To get these devices to work properly for non-root users (specifically the members of usb group), the following rules are set in /etc/devfs.rules:

/etc/devfs.rules
# /etc/devfs.rules
# Time-stamp: <2008-08-08 21:36:28 rsmith>

[slackbox_usb=10]
add path 'da*' mode 0660 group usb
add path 'msdosfs/*' mode 0660 group usb
add path 'uscanner*' mode 0660 group usb
add path 'usb*' mode 0660 group usb
add path 'ugen*' mode 0660 group usb
add path 'tap*' mode 0660 group wheel
add path 'pass*' mode 0660 group cdrom

The first line assigns a name and number to a set of rules. The devfs(8) command only knows about the number, the name is for convenience in the startup script.

The second line assigns read/write permissions for the group usb to all partitions of USB mass-storage devices.

The third line does the same for scanners.

To activate these settings after the next reboot, a line has to be added to /etc/rc.conf:

# Set the default devfs ruleset.
devfs_system_ruleset="slackbox_usb"

Sysctl

The sysctl(8) program allows everybody to examine and root to modify kernel parameters. I have placed the following in my /etc/sysctl.conf file:

/etc/sysctl.conf
# /etc/sysctl.conf
# Time-stamp: &tl;2008-12-27 21:49:01 rsmith>

# Allow normal users to mount filesystems.
vfs.usermount=1

# Speed up disk reads.
vfs.read_max=32

# For X
kern.ipc.shmmax=67108864
kern.ipc.shmall=32768

# Use pcm1 as default.
hw.snd.default_unit=0
dev.pcm.0.play.vchans=4
hw.snd.maxautovchans=4

# Enable port forwarding (for NAT in pf.conf)
net.inet.ip.forwarding=1

# Enable network device polling
kern.polling.enable=1

# Blackhole against portscanning.
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1

# Do not log fatal signal exits. (from §11.10.4 in the Handbook)
kern.logsigexit=0

# More memory for directory hashes.
vfs.ufs.dirhash_maxmem=16777216

With the variable vfs.usermount set, normal users are allowed to mount filesystems, provided they own the mount point..

Security

logins

To prevent logins from elsewhere, the following rule has been set as the only rule in the /etc/login.access file:

-:ALL:ALL EXCEPT LOCAL

This means that only local logins are possible. Do not use this if you want to be able to login remotely!

firewall

My workstation s configured as a client in /etc/rc.conf:

# PF Firewall
pf_enable="YES"

The filtering rules for the pf firewall are contained in /etc/pf.conf:

/etc/pf.conf
# /etc/pf.conf
# Time-stamp: <2008-12-26 12:12:36 rsmith>
# Packet filter configuration for Slackbox.

# Macros: define common values, so they can be referenced and changed easily.
ext_if = "age0"
int_if = "xl0"

# Addresses that can't be routed externally. 
# See http://www.rfc-editor.org/rfc/rfc3330.txt
# (10.0.0.138 is my router, so it should be reachable!)
table <unroutable> const { 0.0.0.0/8, 10.0.0.0/8, !10.0.0.138, 127.0.0.0/8, \
169.254.0.0/16, 172.16.0.0/12, 192.0.2.0/24, 192.168.0.0/16, 240.0.0.0/4 }

# Options: tune the behavior of pf.
set optimization normal
set block-policy drop
set loginterface $ext_if
set skip on lo

# Normalization: reassemble fragments etc.
scrub in all

# Translate outgoing packets' source addresses (any protocol).
# In this case, any address but the gateway's external address is mapped.
# The sysctl net.inet.ip.forwarding should be set for this to work.
# Alternatively, set gateway_enable="YES" in /etc/rc.conf.
nat pass on $ext_if inet from $int_if:network to any -> $ext_if

# Filtering
antispoof quick for $int_if

# Nobody gets in from the outside!
block in log quick on $ext_if all label "inblock"

# Block packets to unroutable addresses
block out log quick on $ext_if from any to <unroutable> label "unroutable"

# Block by default. (pass rules dhould follow later).
block out log on $ext_if all label "outblock"

# Internal "network" is trusted.
pass quick on $int_if all flags any no state

# Let outgoing traffic through, and keep state (which is the default now)
# Not using modulate state becaue that seems to be broken.
pass out on $ext_if inet proto tcp all
pass out on $ext_if inet proto udp all 
# Let pings through.
pass out on $ext_if inet proto icmp all icmp-type 8 code 0

The setup above is designed for a workstation that has no servers running. Outgoing connection are remembered by the firewall, and it lets incoming packets related to outgoing ones in. Other incoming packets are blocked.

daemons

FreeBSD comes with the sensible default of most network daemons disabled (See /etc/defaults/rc.conf).

So if you want e-mail, you'll have to activate sendmail(1) in /etc/rc.firewall, or install and activate another mail daemon. Because I find it easier to configure, I use postfix.

To disable sendmail completely, the following is set in /etc/rc.conf:
sendmail_enable="NONE"

Since sendmail(1) is symlinked to mailwrapper(8), we also need to configure the latter to use postfix, by editing /etc/mail/mailer.conf;

/etc/mailer.conf
#
# Execute the Postfix sendmail program, named /usr/local/sbin/sendmail
#
sendmail        /usr/local/sbin/sendmail
send-mail       /usr/local/sbin/sendmail
mailq   /usr/local/sbin/sendmail
newaliases      /usr/local/sbin/sendmail

malloc.conf

By creating a symbolic link named malloc.conf in /etc, options for the malloc(3) family of library functions can be set. The different options are represented by letters. Capital letters mean that an option is enabled, while lowercase mean that an option is disabled.

# cd /etc; ln -s 'ajHR' malloc.conf

powerd

To reduce the power usage and temperature of my system when it's idling I've enabled powerd(8) in it's default adaptive mode. This is done in two steps.

First, the cpufreq(4) device has to be included in the kernel configuration;

# Control CPU frequency.
device cpufreq

After rebuilding and installing the kernel, powerd has to be enabled in /etc/rc.conf:

# Enable power monitoring.
powerd_enable="YES"

smartd

The smartd(8) daemon monitors the health of SMART capable harddisks. This will warn you before a harddisk fails, so you can make a backup and replace it before you loose your data. It is part of the smartmontools package (in /usr/ports/sysutils), so you have to install that first.

Now a config file, /usr/local/etc/smartd.conf will need to be written. Below is the relevant part of mine:

/dev/ad4 -o on -s (S/../.././02|L/../../6/04) -H \
-l error -l selftest -t -I 194 -I 9 \
-M exec /usr/bin/mail -m rsmith@localhost 
/dev/ad6 -o on -s (S/../.././03|L/../../6/05) -H \
-l error -l selftest -t -I 194 -I 9 \
-M exec /usr/bin/mail -m rsmith@localhost

It is important to use the "-M exec" parameter, because smartd assumes /bin/mail, which doesn't exist on FreeBSD. See the smartd.conf(5) manual page for the meaning of the parameters.

Cache write-through for harddisks

By default, most disk drives cache writes in internal memory before actually committing them to the disk.

This behaviour can make it more likely to trigger inconsistencies on a filesystem using soft updates in case of a power failure. Therefore I have disabled this feature by writing the following in /boot/loader.conf;

# Set ata devices to write-through cache.
hw.ata.wc="0"

X cursor theme

Cursors are themable in Xorg now. I like the redglass theme myself. To implement it, I set the following in my ~/.xinitrc file:

export XCURSOR_THEME=redglass

Additionally, I set the following in my ~/.Xresources file:

! Cursor theme
Xcursor.theme: redglass

This might not be necessary. Most apps work fine with just the environment variable set.

Firefox cursor problem

But Firefox displays the old black/white watch cursor when loading a page. Apparently this is because it's looking for a cursor name that doesn't exist. The following will fix this:

# cd /usr/local/lib/X11/icons/redglass/cursors
# ln -s left_ptr_watch 08e8e1c95fe2fc01f976f1e063a24ccd

This will make Firefox use the left_ptr_watch cursor, which is the normal left_ptr cursor with a blinking watch. You can of course use any of the other cursor to link to, if you like.

The same fix can of course be applied to other cursor themes as well.

Kensington Expert Mouse & Xorg

Instead of a mouse, I prefer using a trackball. But a lot of trackballs are not usable for left-handed people like myself. The one I'm currently using is a Kensington Expert Mouse®. I like it because it has four buttons and a scroll-ring.

To use this trackball with the Xorg server, I put the following in xorg.conf;

Section "InputDevice"
        Identifier  "ExpertMouse"
        Driver      "mouse"
        Option      "Protocol"          "Auto"
        Option      "Device"            "/dev/psm0"
	Option	    "Buttons"	        "6"
	Option	    "ZAxisMapping"      "4 5"
	Option	    "ButtonMapping"     "3 2 1"
        Option      "CorePointer"       "on"
EndSection

The device /dev/psm0 is specific for FreeBSD. Linux users will want to use /dev/mouse.

The ButtonMapping option is used to switch buttons one and three because I'm left-handed. With this option, the button on the lower-right is button one, lower-left is button three and top-left is button two. Rotating the scroll-ring clockwise is button five, anti-clockwise is button four.

Backups

It is essential to make good backups. Disks can fail, operators will make errors, and without backups you will lose data!

Essentially there are two kinds of backups, disaster recorvery and archival storage. In this case I'm more concerned with the former than with the latter, since I keep all my data live on disk where I can reach it.

There are a myriad of applications for making backups, and there are many backup media. On this page, I will only touch on the method and media that I currently use.

My first line of defence is to have two identical disks in the machine. The first one (ad4) is normally used, while the second one (ad6) is a copy which is updated nightly by rsync(1) is a cron(8) job. I tried using gmirror(8), but that felt slow, and rebuilding the array took days.

Having two disks doesn't protect against calamities like fire or theft. So one should consider making backups and storing them away from the PC.

There are a few features that a backup program should have;

  1. Tools for restoring system partitions should be available in the base system or an install CD; If you need to restore, you should be able to do so without first having to install a base system and a bunch of ports. That's a lot of work.
  2. It should back up all the features, data and attributes of the system partitions; If the backup program doesn't restore ownerships, permissions, flags and ACLs you have to restore them by hand afterwards. Again a lot of extra work.

In the /rescue directory of both the FreeBSD base system and the install CD, you'll find statically linked binaries of restore(8) (for restoring backups made by dump(8)), tar(1) and pax(1). But only dump(8)/restore(8) is guaranteed to fullfill the second requirement on UFS2 filesystems. So that is what I use for system partitions.

The bulk of my data is in my /home partition. Things like holiday photos, scans and MP3 files take up a lot of space but change infrequently. Therefore I felt that a weekly level 0 backup was inappropriate for this partition.

The other important consideration is backup media. Traditionally, backups were made on magnetic tape. But tape drives are expensive, and their capacity has not kept up with modern disk sizes. A dump of a large partition can also easily be larger than a recordable DVD. And although it's possible to split dump output into DVD-sized chunks, it is an extra complication. Therefore I use a couple of disks in USB enclosures. Their size is sufficient to store complete backups. They are easy to use and store in a vault or off-site.

Next question is what to back up. It is customary to divide the disk into several partitions. Here is my break-up;

$ df -h
Filesystem         Size    Used   Avail Capacity  Mounted on
/dev/ad4s1a        484M    270M    175M    61%    /
devfs              1.0K    1.0K      0B   100%    /dev
/dev/ad4s1g.eli    373G     69G    274G    20%    /home
/dev/ad4s1e         48G    6.6G     38G    15%    /tmp
/dev/ad4s1f         19G    5.0G     13G    28%    /usr
/dev/ad4s1d        1.9G    1.1G    718M    61%    /var

The /dev filesystem in FreeBSD is filled by the OS, so it doesn't have to be backed up. The /tmp filesystem is only used for temporary storage, so it doesn't need to be backed up either.

So the filesystems that need to be backed up in my case are /, /home, /usr and /var. On can summarize those as all UFS filesystems except /tmp.

If your disk has died, you need to re-partition and newfs your new disk to match the old one. To that end, one should always store a copy of /etc/fstab and the output of the bsdlabel command;

# bsdlabel /dev/ad4s1
# /dev/ad4s1:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a:  1024000       16    4.2BSD     2048 16384 64008 
  b: 16777216  1024016      swap                    
  c: 976768002        0    unused        0     0         # "raw" part, don't edit
  d:  4194304 17801232    4.2BSD     2048 16384 28528 
  e: 104857600 21995536    4.2BSD     2048 16384 28528 
  f: 41943040 126853136    4.2BSD     2048 16384 28528 
  g: 807971826 168796176    4.2BSD     2048 16384     0 

Another thing that is handy to save, is the output of the 'dumpfs -m' command for all of your partitions. This gives you the newfs command to recreate the partitions in question

# dumpfs -m /
# newfs command for / (/dev/ad4s1a)
newfs -O 2 -a 8 -b 16384 -d 16384 -e 2048 -f 2048 -g 16384 -h 64 -m 8 -o time -s 256000 /dev/ad4s1a
# dumpfs -m /home
# newfs command for /home (/dev/ad4s1g.eli)
newfs -O 2 -U -a 8 -b 16384 -d 16384 -e 2048 -f 2048 -g 16384 -h 64 -m 8 -o time -s 201992956 /dev/ad4s1g.eli
# dumpfs -m /usr
# newfs command for /usr (/dev/ad4s1f)
newfs -O 2 -U -a 8 -b 16384 -d 16384 -e 2048 -f 2048 -g 16384 -h 64 -m 8 -o time -s 10485760 /dev/ad4s1f
# dumpfs -m /var
# newfs command for /var (/dev/ad4s1d)
newfs -O 2 -U -a 8 -b 16384 -d 16384 -e 2048 -f 2048 -g 16384 -h 64 -m 8 -o time -s 1048576 /dev/ad4s1d

My method of choice is to use dump(8) to make backups to a USB disk for the system partitions, and use rsync(1) for /home.

The usb disk is devided into a single slice, with two partitions, as described in the USB disk section.

First, the system partitions are backed up;

# rm -rf /usr/obj/*
# src/scripts/dodumps 0 /tmp
# mount /dev/da0s1a /mnt/root
# rm -f /mnt/root/*.dump
# cp -vp /tmp/*.dump /mnt/root
# umount /mnt/root

Then the encrypted partition is mounted and the /home partition is syncronized;

# geli attach /dev/da0s1d
# mount /dev/da0s1d.eli /mnt/root
# rsync -axq --delete /home/ /mnt/root/home
# sync
# umount /mnt/root
# geli detach /dev/da0s1d.eli

make.conf

This file is read (via sys.mk) by make(1) every time it runs. It follows makefile syntax and is used to set variables for make.

There are variables that are used for configuration of the system during a 'make buildworld' or 'make kernel'. These will be covered first.

In 7.x part of the system configuration was moved to a separate file, src.conf.

It is also possible to set variables only when building in a specific directory. This is used for configuring ports(7).

System builds

Following is an annotated example of settings I've put in my make.conf. They are listed here as examples only. Do not senselessly copy them! They will probably not be correct for your system and might ruin it when you use them. You have been warned!

The first thing I specify is the type of CPU that the system should be built for.

# Type of CPU the system is built for.
CPUTYPE=athlon64

I'm running the amd64 version of FreeBSD on my Athlon64 based computer. Do not copy this setting unless you know that it is correct! Reading /usr/share/mk/bsd.cpu.mk gives you an idea what types are available, and what they do.

Next is defining the kernel configuration.

# Kernel configuration
KERNCONF=RFS

I've placed a file called RFS in the directory /usr/src/sys/amd64/conf. This file contains a description of which drivers and features I want the kernel to contain. In general, you should place your kernel configuration file (if you don't want to use the standard kernel named GENERIC) in /usr/src/sys/[arch]/conf, where [arch] is the machine architecture of your system. For most people this should be i386.

Moving on to documentation. To save on disk space, and because it is probably the most complete, I only install the English documentation.

# Documentation languages
DOC_LANG=en_US.ISO8859-1

The following was added when the perl port was installed. Do not remove these.

# added by use.perl 2006-05-10 18:26:02
PERL_VER=5.8.8
PERL_VERSION=5.8.8

Ports

The following variables are used to configure certain ports. You can specify these variables when you invoke make to build a port, but this way you can't forget them.

A lot of ports use options these days. This presents you with a nice dialog where you can select features that you want in a port. But not all ports have been option-ized, and some things cannot be set with the options mechanism. To see what variables you can set, look through /usr/ports/[category]/[portname]/Makefile.

The statements like .if ${.CURDIR:M*/foo/bar mean that if make is invoked in a directory that ends in foo/bar, it should set the variables named in the .if/.endif block.

# Flags for different ports
.if ${.CURDIR:M*/print/cups*}
CUPS_OVERWRITE_BASE=true
.endif

.if ${.CURDIR:M*/x11/rxvt-unicode}
WITHOUT_IMLOCALE_FIX=yes 
WITHOUT_PERL=yes 
WITHOUT_UNICODE3=yes 
WITHOUT_MENUBAR=yes 
WITHOUT_RXVT_SCROLLBAR=yes 
WITHOUT_NEXT_SCROLLBAR=yes 
WITHOUT_XTERM_SCROLLBAR=yes 
WITHOUT_PLAIN_SCROLLBAR=yes 
WITHOUT_BACKSPACE_KEY=yes 
WITHOUT_DELETE_KEY=yes 
WITHOUT_LINESPACE=yes
WITHOUT_TERMINFO=yes
WITHOUT_AFTERIMAGE=yes
.endif

.if ${.CURDIR:M*/multimedia/ffmpeg}
WITH_FREETYPE2=yes 
WITH_MP3=yes 
WITH_OPTIMIZED_CFLAGS=yes 
WITHOUT_FFMPEG_FFSERVER=yes
.endif

.if ${.CURDIR:M*/mail/mutt-devel}
WITH_MUTT_SLANG2=yes 
WITHOUT_MUTT_HTML=yes 
WITHOUT_MUTT_XML=yes 
WITHOUT_MUTT_COMPRESSED_FOLDERS=yes 
WITHOUT_NLS=yes 
NOPORTDOCS=yes
.endif

.if ${.CURDIR:M*/graphics/povray}
WITH_OPTIMIZED_FLAGS=yes
.endif

.if ${.CURDIR:M*/multimedia/mplayer}
WITH_DVD_DEVICE=/dev/cd0
WITH_CDROM_DEVICE=/dev/cd0
.endif

.if ${.CURDIR:M*/math/octave}
WITH_BLAS=yes
.endif

.if ${.CURDIR:M*/sysutils/conky}
WITH_XFT=yes
.endif

.if ${.CURDIR:M*/graphics/xd3d}
WITHOUT_GIFSICLE=yes
.endif

.if ${.CURDIR:M*/print/ghostscript*}
A4=yes
BATCH=yes
.endif

.if ${.CURDIR:M*/editors/emacs*}
WITHOUT_GTK=yes
.endif

.if ${.CURDIR:M*/security/pinentry}
PINENTRY_GTK2=yes
.endif

.if ${.CURDIR:M*/security/isomaster}
WITHOUT_NLS=yes
.endif

.if ${.CURDIR:M*/devel/git}
WITHOUT_GUI=yes
.endif

.if ${.CURDIR:M*/lang/gcc*}
WITHOUT_JAVA=yes
.endif

.if ${.CURDIR:M*/x11-servers/xorg-server}
WITHOUT_HAL=yes
.endif

src.conf

In 7.x, most of the base system configuration has been moved to src.conf, as not to interfere with building ports.

Below is my src.conf as an example. Do not copy this to your system, but read src.conf(5) and figure out what you should use.

# /etc/src.conf
# Time-stamp: <2007-10-26 08:20:46 rsmith>

WITHOUT_ATM=true
WITHOUT_BLUETOOTH=true
WITHOUT_CDDL=true
WITHOUT_I4B=true
WITH_IDEA=true
WITHOUT_IPFILTER=true
WITHOUT_IPX=true
WITHOUT_LIB32=true
WITHOUT_LIBKSE=true
WITHOUT_LPR=true
WITHOUT_NCP=true
WITHOUT_PROFILE=true
WITHOUT_RCMDS=true
WITHOUT_SENDMAIL=true

Disk encryption

After I had a computer of mine stolen, I decided to better secure my data. To that end switched over to encrypted backup disks, and an encrypted /home partition. Since most computer users wouldn't know what to do with a UFS partition, one can debate if this is necessary. But it does protect your data against more sophisticated attackers.

I didn't bother encrypting more partitions, although one could make the case that /tmp and /var should be encrypted as well.

What is commonly known as partitions are called slices in FreeBSD, because of it's UNIX heritage which predates the PC. In FreeBSD a partition is a subdivision of a slice. For instance, the /dev/ad0s1d device is the 'd' partition on the first slice 's1' of the first disk 'ad0'.

USB backup disk

For backups, I use an external harddisk with a USB connection. This device uses the umass driver, which in turn needs the scbus and da devices.

This disk has a single BSD slice, devided into two partitions. The first 20BG partition (da0s1a) is for the dumps of /, / usr a /var. The rest of the disk is a geli(8) encrypted partition (da0s1d.eli) to store data from home.

# fdisk -I /dev/da0
# bsdlabel -w /dev/da0s1
# setenv EDITOR /usr/bin/ee
# bsdlabel -e /dev/da0s1

The EDITOR variable is set to a somwhat friendlier editor then the default vi(1)!

Next, the slices are made.

# /dev/da0s1:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a: 20971520       16    4.2BSD     2048 16384 28528 
  c: 488392002        0    unused        0     0         # "raw" part, don't edit
  d: 467420466 20971536    4.2BSD        0     0     0 

The d partition is encrypted;

# geli init -l 256 /dev/da0s1d
# geli attach /dev/da0s1d

for better security, I then filled the second partition with random data;

# dd if=/dev/random of=/dev/da0s1d bs=32k

After that, I initialised GEOM_ELI for that partition with geli(8), and attached it;

# geli init -l 256 /dev/da0s1d 
# geli attach /dev/da0s1d

The initialization needs to be done only once. Attaching must be done to to create the /dev/da0s1d.eli device. The 'geli init' command will ask you to choose a password, and confirm it. Attaching a device also asks for the password.

Now that the devices exists, we can create filesystems on it;

# newfs -U /dev/da0s1a
# newfs -U /dev/da0s1d.eli

/home

During system install, I chose to put /home on a separate partition. It is currently not possible to create encrypted filesystems with sysinstall(8). So this has to be done afterwards.

If you want to use encrypted filesystems, you'll need the initialization scripts /etc/rc.d/geli and /etc/rc.d/geli2. They are present in 6.x.

The first step is to make a level 0 dump of /home if you have any data on it. This dump should be put on another partition, since the partition for /home will be completely overwritten in the process. Look into /etc/fstab to see which device /home is on;

/dev/ar0s1g         /home           ufs     rw              2       2

Now it is time to completely log out all normal users, and login as root. Next unmount /home.

# umount /home

If the GEOM_ELI device is not compiled into the kernel, make sure that it is loaded as a module.

# kldload geom_eli.ko

To make sure that this module is loaded after the next reboot, add the following to /boot/loader.conf. Again, you only need to do this when GEOM_ELI isn't compiled into the kernel;

geom_eli_load="YES"

As the next step we overwrite the partition with random data, to make the encrypted filesystem data harder to spot.

# dd if=/dev/random of=/dev/ar0s1g bs=32k

At this point it might still be possible to retrieve the previous contents of the filesystem. So if you're really paranoid, you'll want to wipe the partition before writing the random data.

The next steps are to initialize, attach and mount the encrypted device.

# geli init -l 256 /dev/ar0s1g
# geli attach -d /dev/ar0s1g
# newfs -U /dev/ar0s1g.eli
# mount /dev/ar0s1g.eli /home

At the next boot, the system will ask you for the password for the encrypted partition, before you log in.

Additional software

Most of the additional software on my system is installed via the ports system. If you want to install a piece of additional software, look if it's in ports first!

TeXLive

TeXLive is a very feature-rich and well-integrated TeX distribution. It contains more that the standard teTeX distribution in ports, so I choose to install this.

First I installed the system files from the CD that I got as an NTG member. It includes a shell-script to install things. The base directory that I used was /usr/local/share/tex/.

Because the TeXLive distribution does not come with FreeBSD amd64 binaries (it has i386 binaries, though) I had to compile the system myself, which was not very hard.

First, the source code is unpacked and configured:

$ cd tmp/
$ mkdir foo; cd foo
$ tar xvzf source.tar.bz2
$ ./configure --prefix=/usr/local/texlive/2005 --without-dvi2tty 
--without-omega --without-musixflx --without-omega --enable-ipc 
--with-system-ncurses --with-system-pnglib --with-system-t1lib 
--with-system-zlib --with-system-gd --with-system-freetype

The build failed for omega, which I don't use anyway, so I patched TeX/texk/web2c/Makefile to disable it:

--- Makefile.orig       Tue Feb 28 01:10:46 2006
+++ Makefile    Tue Feb 28 01:22:05 2006
@@ -1143,10 +1143,10 @@
 
 Makefile: omegadir/omega.mk
 
-omegafonts_programs = omegafonts/omfonts
-otps_programs = otps/otp2ocp otps/outocp
-omegafonts = omegafonts
-otps = otps
+#omegafonts_programs = omegafonts/omfonts
+#otps_programs = otps/otp2ocp otps/outocp
+#omegafonts = omegafonts
+#otps = otps
 
 odvicopy = odvicopy
 odvitype = odvitype
@@ -1155,7 +1155,7 @@
 omegaware_programs = $(otangle) $(odvicopy) $(odvitype)
 
 omega_programs = $(omega) $(otangle) $(odvicopy) $(odvitype) \
-                 $(otps_programs) $(omegafonts_programs)
+                 #$(otps_programs) $(omegafonts_programs)
 
 # The otangle used in the build is not be the otangle we build if we are
 # cross-compiling.
@@ -1336,12 +1336,12 @@
 # ^L
 # Some additional programs for Omega: the programs themselves are named
 # in the variable otps_programs, defined above.
-otps/otp2ocp:
-       cd otps && $(MAKE) $(common_makeargs) otp2ocp
+#otps/otp2ocp:
+#      cd otps && $(MAKE) $(common_makeargs) otp2ocp
 otps/outocp:
        cd otps && $(MAKE) $(common_makeargs) outocp
-omegafonts/omfonts:
-       cd omegafonts && $(MAKE) $(common_makeargs) omfonts
+#omegafonts/omfonts:
+#      cd omegafonts && $(MAKE) $(common_makeargs) omfonts
 # ^L
 # Installation.
 install-omega: install-omega-exec install-omega-data
@@ -1354,11 +1354,11 @@
 install-omega-programs: $(omega_programs) $(bindir)
        for p in omega; do $(INSTALL_LIBTOOL_PROG) $$p $(bindir); done
        cd otps && $(MAKE) $(install_makeargs) install-programs
-       cd omegafonts && $(MAKE) $(install_makeargs) install-programs
+       #cd omegafonts && $(MAKE) $(install_makeargs) install-programs
 
 install-links: #!  install-omega-links
 install-omega-links: install-omega-programs
-       cd omegafonts && $(MAKE) $(install_makeargs) install-links
+       #cd omegafonts && $(MAKE) $(install_makeargs) install-links
        #cd $(bindir) && (rm -f iniomega viromega; \
        #  $(LN) omega iniomega; $(LN) omega viromega)
 
@@ -1905,7 +1905,7 @@
           $(pdftex) $(pdfetex)
 
 programs: $(programs) $(engines) $(mpware_programs) \
-          $(omegafonts_programs) $(otps_programs) $(pdftosrc)
+          $(otps_programs) $(pdftosrc)
 
 # Additional dependencies for relinking.
 # Note that each program and engine already depends on $(web2c_programs).
@@ -2555,7 +2555,7 @@
 
 # ^L
 # Cleaning.
-all_subdirs = doc lib man $(mpware) web2c window $(omegafonts) $(otps) $(pdftex
dir) $(pdfetexdir)
+all_subdirs = doc lib man $(mpware) web2c window $(otps) $(pdftexdir) $(pdfetex
dir)
 
 # Having a multiple-target rule with the subdir loop fails because of
 # the dependencies introduced by clean.mk.  Yet, we want the

Use gmake instead of the normal make, otherwise the build will fail. Of course the ports png and t1lib should be installed first;

$ gmake
$ su
# gmake install

To use the binaries, I had to add /usr/local/texlive/2005/bin/x86_64-unknown-freebsd6.0 to the path of the default class in /etc/login.conf.

To make it all work correctly, I had to stop TeX from trying to use the Omega fonts. To do that, I copied /usr/local/texlive/2005/texmf/web2c/updmap.cfg to /usr/local/texlive/2005/texmf-var/web2c/updmap.cfg and removed the line

Map omega.map

After that I had to run updmap as root to make TeX aware of the change.

By default, a lot of hyphenations are enabled in TeXLive. I used texconfig(1) to disable the ones I don't use.

DIY monitor system

As described on my desktop page, I'm using torsmo to display system data. But I also wanted some graphs of system temperatures and network traffic.

The process of creating and displaying these graphs is divided in multiple steps:

  1. Collect data in cronjobs, and save them to files.
  2. Create graphs that resemble torsmo output in style from the collected data, also in a cron(8) job.
  3. Display the graphs on the desktop with telak that resemble torsmo output in style.

For generating a temperature graph, steps one and two are combined in a shell-script called tempmon.sh, which is called every minute as a cron(8) job. This script uses mbmon(1), part of the xmbmon package, to collect temperature data. Using grep(1) and cut(1) the relevant data is selected from the mbmon(1) output, and then written to a file. The file is limited to 60 lines, representing data for the last hour. The gnuplot(1) program is then used to make a graph of the data. The background color of the graph matches the desktop background, and the graph colors match those used in my torsmo(1) setup. An example is displayed below.

CPU and case temperature graph.

Data about the network usage is gathered by pfstat(8) running every minute as a cron(8) job. Its output is written to /var/log/pfstat. The netdata.pl script selects the appropriate portions of the /var/log/pfstat file, and converts the absolute byte counts to average kB/s values. It writes two files; one containing the data for the last hour, and one containing the data for the last day. With the instructions contained in netplot.gp, data files are then used by gnuplot(1) to generate two graphs. One of stacked bar graph of incoming and outgoing bytes over the last hour. The second of combined network traffic over the last 24 hours. Examples of both graphs are shown below:

Graph of the network traffic in the last hour. Graph of the network traffic over the last 24 hours.

The data-gathering scripts are run every minute via cron:

# Crontab for root.
# Time-stamp: <2006-07-25 09:28:10 rsmith>

#minute hour mday month wday command

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
MDDIR=/usr/local/share/monitor
MAILTO=rsmith

#<monitor> Log data from pf every minute. pfstat version 1.7!
* * * * * pfstat -q >>/var/log/pfstat
# <monitor> Limit the size of the logfile.
1 1 * * 1 tail -n 20000 /var/log/pfstat >/tmp/pfstat; mv /tmp/pfstat /var/log/pfstat

# <monitor> Graph the network data every minute
* * * * * perl $MDDIR/netdata.pl; gnuplot $MDDIR/netplot.gp

# <monitor> Gather and graph CPU and case temperature data every minute. 
* * * * * sh $MDDIR/tempmon.sh

The graphs are displayed on the desktop by telak, started via ~/.xinitrc. The configuration to show the graphs is as follows:

[temp]
url = /usr/tmp/temp.png
width = 300
height = 150
x = 0
y = 160
refresh = 60

[net_hour]
url = /usr/tmp/net_hour2.png
width = 300
height = 150
x = 0
y = 320
refresh = 60

[net_day]
url = /usr/tmp/net_day2.png
width = 300
height = 150
x = 0
y = 480
refresh = 60

The result is that the graphs fit well into the desktop. See my desktop page.