Mounting Disk Images
Memory disks can also be used to mount and access disk images. This is most
useful for viewing the contents of CD images without burning them to disk.
Just attach a memory disk to a file with the mdconfig(8) command’s -a flag.
Here, I attach a FreeBSD ISO to a memory device:
We tell mdconfig(8) to attach a vnode-backed memory device to the
file specified . mdconfig(8) responds by telling us the device. it’s attached
to. Now we just mount the device with the proper mount command for the
filesystem:
# mount -t cd9660 /dev/md0 /mnt
One common mistake people make at this point is mounting the image
without specifying the filesystem type. You might get an error, or you might
get a successful mount that contains no data—by default, mount(8) assumes
that the filesystem is FFS!
When you’re done accessing the data, be sure to unmount the image
and destroy the memory disk device just as you would for any other memory
device. While vnode-backed memory disks do not consume system memory,
leaving unused memory devices around will confuse you months later when
you wonder why they appear in /dev. If you’re not sure what memory devices
a system has, use mdconfig -l to view all configured md(5) devices.
# mdconfig -l
md0 md1
I have two memory devices? Add the -u flag and the device number to
see what type of memory device it is. Let’s see what memory device 1
(/dev/md1) is:
I have an ISO image mounted on this system? Wow. I should probably
reboot some month. Nah, thats too much work, I’ll just unmount the
filesystem.
Filesystems in Files
One trick used for jails (see Chapter 9) and homebrew embedded systems
(see Chapter 20) is building complete filesystem images on a local filesystem.
In the previous section, we saw how we could use memory disks to mount
and access CD disk images. You can use the same techniques to create,
update, and access FFS disk images. The downside of this is that each image
takes up an amount of disk space equal to the size of the disk image. If you
create a 500MB disk image, it takes up a full 500MB of space.
To use a filesystem in a file, you must create a file of the proper size,
attach the file to a memory device, place a filesystem on the device, and
mount the device.
Creating an Empty Filesystem File s
The filesystem file doesn’t initially contain any data; rather, it’s just a file
of the correct size for the desired filesystem. You could sit down and type a
whole bunch of zeroes to create the file, but FreeBSD provides a unlimited
source of nothing to save you the trouble. The /dev/zero device is chock full of
emptiness you can use to fill the file.
Use the same dd(1) command you used to copy the installation floppy
images to your filesystem file. Here we copy data from /dev/zero and to the file
filesystem.file:
We take our data from the input file /dev/zero and dump it to the
output file filesystem.file. Each transfer occurs in blocks of 1K , and we
do this one million times . This takes a few seconds to complete, but as
/dev/zero doesn’t have to generate the next character, the file fills quickly . If
you look in your current directory, you now have a 1GB file called filesystem.file.
One common source of confusion with dd(1) is the block size and
count. Calculating the final size of a file with dd(1) is like moving a pile of
sand; you break the job into loads and move a number of those loads. You
can use several loads with a wheelbarrow, many loads with a bucket, or lots
and lots of loads with a spoon. The size of each load is the block size, and the
number of trips is the count. Perhaps you’re using your bare hands, which
would correspond to a small block size and a high count. Maybe you have a
wheelbarrow, for a medium block size and a moderate count. Perhaps you
have a steam shovel and can do the whole job in one scoop. The larger the
block size, the more load you put on the system with each block. dd(1)
recognizes a variety of abbreviations for increasing block size and count,
as shown in Table 8-2.
Suppose you want a 1GB file. Remember that 1k is actually one kilobyte.
One megabyte is a thousand kilobytes, and one gigabyte is one thousand
megabytes. If you use a block size of 1 byte, and a count of one gig, you’re
asking your system to make 1,073,741,824 trips to the sand pile. Each trip is
very easy, but there’s an awful lot of them! On the other hand, if you select a
block size of one gig and a count of 1, you’re asking the system to pick up the
whole pile at once. It will not be pleased. Neither will you. Generally speaking,
a block size of 1m and a lower count produces reasonably quick results without
overburdening your system. When you use a 1m block, the count equals the
number of megabytes in the file. A count of 1k creates a 1GB filesystem, a
count of 2k creates a 2GB filesystem, a count of 32 creates a 32MB filesystem,
and so on.
Creating the Filesystem on the File
To get a filesystem on the file, you must first associate the file with a device
with a vnode-backed memory disks. We did exactly this in the last section:
# mdconfig -a -t vnode -f filesystem.file
md0
Now, let’s make a filesystem on this device. This is much like creating an
FFS filesystem on a floppy disk with the newfs(8) command. We specify the
-U flag to enable soft updates on this filesystem, as soft updates are useful on
file-backed filesystems.
# newfs -U /dev/md0
/dev/md0: 1024.0MB (2097152 sectors) block size 16384, fragment size 2048
using 6 cylinder groups of 183.77MB, 11761 blks, 23552 inodes.
with soft updates
super-block backups (for fsck -b #) at:
160, 376512, 752864, 1129216, 1505568, 1881920
newfs(8) prints out basic information about the disk such as its size,
block and fragment sizes, and the inode count.
Now that you have a filesystem, mount it:
# mount /dev/md0 /mnt
Congratulations! You now have a 1GB file-backed filesystem. Copy files to
it, dump it to tape, or use it in any way you would use any other filesystem. But
in addition to that, you can move it just like any other file. We’ll make use of
this when we talk about jails in the next chapter, and it’s a vital technique
for building your own embedded systems.
File-Backed Filesystems and /etc/fstab
You can mount a file-backed filesystem automatically at boot with the proper
entry in /etc/fstab, much like you can automatically mount any other memory
disk. You simply have to specify the name of the file with -F, and use -P to tell
the system to not create a new filesystem on this file but just to use the one
already there. Here we mount the file-backed filesystem we created on /mnt
automatically at boot time. (I told you we’d see /etc/fstab entries uglier than
the one we created for generic memory disks, didn’t I?)
FreeBSD supports several lesser-known filesystems. Most of them are useful
only in bizarre circumstances, but bizarre circumstances arise daily in system
administration.
devfs(5) is the device filesystem used for /dev. You cannot store normal
files on a devfs filesystem; it only supports device nodes. The kernel and the
device filesystem daemon devd(8) directly manage the contents of a device
filesystem.
procfs(5) is the process filesystem; it contains lots of information about
processes. It’s considered a security risk and is officially deprecated on modern
FreeBSD releases. You can learn a lot about processes from a mounted process
filesystem, however. A few older applications still require a process filesystem
mounted on /proc; if a server application requires procfs, try to find a similar
application that does the job without requiring it.
If you’re using Linux mode (see Chapter 12), you might need the Linux
process filesystem linprocfs(5). Much Linux software requires a process
filesystem, and FreeBSD suggests installing linprocfs at /compat/linux/proc
when you install Linux mode. I’d recommend only installing linprocfs if a
piece of software complains it’s not there.
fdescfs(5), the file descriptor filesystem, offers a filesystem view of file
descriptors for each process. Some software is written to require fdescfs(5).
It’s less of a security risk than procfs, but still undesirable.
WIRING DOWN DEVICES
SCSI disks don’t always power up in the same order, but FreeBSD numbers
SCSI drives in the order that they appear on the SCSI bus. As such, if
you change the devices on your SCSI bus, you change the order in which
they’re probed. What was disk 0 when you installed FreeBSD could become
disk 1 after you add a new disk drive. This change would cause partitions to
be mounted on the wrong mount points, possibly resulting in data damage.
You can have similar problems with SCSI buses—if you add another SCSI
interface, your buses can be renumbered! What was /dev/da0 when you
installed FreeBSD could become /dev/da1 or even /dev/da17 after you add
a new tape drive. This causes FreeBSD to mount partitions on the wrong
mount points.
To prevent this problem, you can hard-code disk numbering into the
kernel, a process called wiring down the SCSI devices. To wire down the device
you need the SCSI ID, SCSI bus number, and LUN (if used) of each device
on your SCSI chain, available in /var/run/dmesg.boot. For example, on a test
system I have the following dmesg entries for my SCSI adapter:
ahc0: <Adaptec 2940B Ultra2 SCSI adapter> port 0xe000-0xe0ff mem 0xe80420000xe8042fff
irq 11 at device 20.0 on pci0
aic7890/91: Ultra2 Wide Channel A, SCSI Id=7, 32/253 SCBs
The first line shows that the main SCSI card is an Adaptec 2940B Ultra2
adapter. The second line gives us more information about the chipset on this
card. This is really only one physical card. The host adapter is using SCSI ID 7,
and no LUN.
A little later in dmesg.boot I have entries for all SCSI disks. While these
entries include things such as disk capacity, model, speed, and features, the
first line for each disk looks much like these:
This tells us that the disk da0 is on SCSI card ahc0 , on SCSI bus 0 ,
at SCSI ID 8 , at LUN 0 . Disk da1 is on the same card and bus, at SCSI
ID 9 .
To wire down a drive, tell the kernel exactly what SCSI bus number to
attach to which SCSI card, and then the SCSI ID and LUN of each disk. Do
this with kernel hints in /boot/device.hints:
Here, we’ve told FreeBSD to attach SCSI bus number 0 to card
ahc0 . Disk da0 is attached to SCSI bus 0 at SCSI ID 8 , and disk da1
is attached to the same bus at SCSI ID 9 . On your next reboot the drives
will be numbered as you configured. If you add another SCSI card, or more
SCSI hard drives, FreeBSD configures the new drives and buses with unit numbers
other than those you’ve reserved for these devices. You can also use lun
hints if you have targets with multiple LUNs.
ADDING NEW HARD DISKS
Before you can use a new hard drive, you must slice it, create filesystems,
mount those filesystems, and move data to them. While FreeBSD has
command-line tools that can handle all this for you, the simplest and fastest
way is with sysinstall(8). We’ll assume that you are adding disks to an existing
system, and that your eventual goal is to move a part of your data to this disk.
BACK UP, BACK UP, BACK UP!
Before doing anything with disks, be sure that you have a complete backup. A single dumb fat-finger mistake in this process can destroy your system! Whie you rarely
plan to reformat your root filesystem, if it happens you want to recover really, really quickly.
Creating Slices
Your first task in preparing your new hard disk is to create a slice and
partition it. Follow these steps:
Become root and start sysinstall(8). Choose Configure, and then Disk.
This menu should look somewhat familiar; you used it when you installed
FreeBSD. (You can see screenshots in Figure 2-4 in Chapter 2.) You’ll see
your existing FreeBSD disks and your new disk. Choose the new disk.
If this disk is recycled from another server, you might find that it has a
filesystem on it. It’s usually simplest to remove the existing partitions and
start over. Use the arrow keys to move to any existing partitions, and
press D to delete them.
Either create a slice by pressing C, or just use the whole disk by pressing A.
In a server, you almost certainly want to use the entire disk. When you’ve
chosen your slices, make the changes effective immediately by pressing W.
You’ll see a warning like this:
WARNING: This should only be used when modifying an EXISTING installation.
If you are installing FreeBSD for the first time then you should simply
type Q when you're finished here and your changes will be committed in one
batch automatically at the end of these questions. If you're adding a
disk, you should NOT write from this screen, you should do it from the
label editor.
Are you absolutely sure you want to do this now?
Yes, you’re absolutely sure. Tab over to Yes and hit ENTER.
You’ll then be asked if you want to install a boot manager on this disk.
Additional disks don’t need boot managers, so arrow down to Standard
and press the spacebar. The sysinstall program tells you that it has written
out the fdisk information successfully. You now have a FreeBSD slice on
the disk. Hit Q to leave the fdisk part of sysinstall.
Creating Partitions
To create partitions on your disk, follow these steps:
Choose the Label option of sysinstall(8), on the same submenu as
FDISK. Select your new disk to reach the disklabel editor. Here you can
create a new partition with the C command, specifying its size in either
megabytes, gigabytes, disk blocks, or disk cylinders. You can also decide
if each new partition will be a filesystem or swap space. When you’re
asked for a mount point, use /mnt for the moment. Sysinstall temporarily
mounts the new partition at that location.
When the disk is partitioned as you need, press W to commit the
changes. You’ll get the same warning you saw in the fdisk menu, and
then messages from newfs(8).
Once newfs(8) finishes, exit sysinstall.
Configuring /etc/fstab
Now tell etc/fstab about your new disks. The configuration differs depending
on whether the new partition is a filesystem or swap space. Every swap space
entry in etc/fstab looks like this:
devicename none swap sw 0 0
If your new swap partition is /dev/da10s1b, you would add this line to
etc/fstab:
/dev/da10s1b none swap sw 0 0
Upon your next reboot, FreeBSD will recognize this swap space. You can
also use swapon -a devicename to activate new swap without rebooting.
If you created a data partition, add a new entry as described earlier in
this chapter, much like this:
/dev/da10s1d /usr/obj ufs rw 2 2
Now you can just unmount the new partition from its temporary location,
run mount /usr/obj, and your new disk is ready for files.
Installing Existing Files onto New Disks
Chances are that you intend your new disk to replace or subdivide an
existing partition. You’ll need to mount your new partition on a temporary
mount point, move files to the new disk, then remount the partition at the
desired location.
In our example above, we’ve mounted our new partition on /mnt. Now
you just need to move the files from their current location to the new disk
without changing their permissions. This is fairly simple with tar(1). You can
simply tar up your existing data to a tape or a file and untar it in the new
location, but that’s kind of clumsy. You can concatenate tar commands to
avoid that middle step, however.
# tar cfC - /old/directory . | tar xpfC - /tempmount
If you don’t speak Unix at parties, this looks fairly stunning. Let’s
dismantle it. First, we go to the old directory and tar up everything. Then
pipe the output to a second command, which extracts the backup in the new
directory. When this command finishes, your files are installed on their new
disk. For example, to move em/usr/src/em onto a new partition temporarily mounted
at /mnt, you would do this:
# tar cfC - /usr/src . | tar xpfC - /mnt
Check the temporary mount point to be sure that your files are actually
there. Once you’re confident that the files are properly moved, remove the
files from the old directory and mount the disk in the new location. For
example, after duplicating your files from /usr/src, you would run:
# rm -rf /usr/src/*
# umount /mnt
# mount /usr/src
MOVING LIVE FILES
You cannot safely move fies that are changing as you copy. For example, if you’re
moving your email spool to a new partition, you must shut down your mail server
first. Otherwise, files change as you’re trying to copy them. Tools such as rsync/usr/ ports/net/rsync can hep reduce outage duration, but an interruption is still necessary.
Stackable Mounts
Suppose you don’t care about your old data; you simply want to split an existing
disk to get more space and you plan to recover your data from backup.
Fair enough. All FreeBSD filesystems are stackable. This is an advanced idea
that’s not terribly useful in day-to-day system administration, but it can bite
you when you try to split one partition into two.
Suppose, for example, that you have data in /usr/src. See how much space
is used on your disk, and then mount a new empty partition on /usr/src. If you
look in the directory afterwards, you’ll see that it’s empty.
Here’s the problem: The new partition is mounted "above" the old disk,
and the old disk still has all that data on it. The old partition has no more
free space than before you moved the data. If you unmount the new partition
and check the directory again, you’ll see the data miraculously restored! The
new mount obscured the lower partition.
Although you cannot see the data, data on the old disk still takes up
space. If you’re splitting a disk to gain space, and you just mount a new disk
over part of the old, you won’t free any space on your original disk. The
moral is: Even if you are restoring your data from backup, make sure that
you remove that data from your original disk to recover disk space.
NETWORK FILESYSTEMS
A network filesystem allows accessing files on another machine over the
network. The two most commonly used network filesystems are the original
Network File System (NFS) implemented in Unix, and the CIFS (aka SMB)
filesystem popularized by Microsoft Windows. We’ll touch on both of these,
but start with the old Unix standard of NFS.
Sharing directories and partitions between Unix-like systems is perhaps
the simplest Network File System you’ll find. FreeBSD supports the Unix
standard Network File System out of the box. Configuring NFS intimidates
many junior system administrators, but after setting up a file share or two
you’ll find it not so terribly difficult.
Each NFS connection uses a client-server model. One computer is the
server; it offers filesystems to other computers. This is called NFS exporting,
and the filesystems offered are called exports. The clients can mount server
exports in a manner almost identical to that used to mount local filesystems.
One interesting thing about NFS is its statelessness. NFS does not keep
track of the condition of a connection. You can reboot an NFS server and the
client won’t crash. It won’t be able to access files on the server’s export while
the server is down, but once it returns, you’ll pick up right where things left
off. Other network file sharing systems are not always so resilient. Of course,
statelessness also causes problems as well; for example, clients cannot know
when a file they currently have open is modified by another client.
NFS INTEROPERABILITY
Every NFS implementation is slightly different. You’ll find minor NFS variations between
Solaris, Linux, BSD, and other Unix-like
systems. NFS shoud work between them all, but might require the occasional tweak. If you’re having problems with another
Unix-like
operating system, check the FreeBSD-net mailing list archive; the issue has
almost certainly been discussed there.
Both NFS servers and clients require kernel options, but the various NFS
commands dynamically load the appropriate kernel modules. FreeBSD’s
GENERIC kernel supports NFS, so this isn’t a concern for anyone who
doesn’t customize their kernel.
NFS is one of those topics that have entire books written about them.
We’re not going to go into the intimate details about NFS, but rather focus
on getting basic NFS operations working. If you’re deploying complicated
NFS setups, you’ll want to do further research. Even this basic setup lets you
accomplish many complicated tasks.
Enabling the NFS Server
Turn on NFS server support with the following rc.conf options. While not all
of these options are strictly necessary for all environments, turning them all
on provides the broadest range of NFS compatibility and decent out-of-the-
box performance.
First, tell FreeBSD to load the nfsserver.ko kernel module, if it’s not
already in the kernel. rpcbind(8) maps remote procedure calls (RPC) into
local network addresses. Each NFS client asks the server’s rpcbind(8) daemon
where it can find a mountd(8) daemon to connect to. mountd(8) listens
to high-numbered ports for mount requests from clients. Enabling the NFS
server also starts nfsd(8), which handles the actual file request. rpc.lockd(8)
ensures smooth file locking operations over NFS, and rpc.statd(8) monitors
NFS clients so that the NFS server can free up resources when the host
disappears.
While you can start all of these services at the command line, if you’re
just learning NFS it’s best to reboot your system after enabling NFS server.
Afterwards, you’ll see rpc.lockd, rpc.statd, nfsd, mountd, and rpcbind listed
in the output of sockstat(1). If you don’t see all of these daemons listening
to the network, check /var/log/messages for errors.
Configuring NFS Exports
Now tell your server what it can share, or export. We could just export all
directories and filesystems on the entire server, but any competent security
administrator would have a (justified) fit. As with all server configurations,
permit as little access as possible while still letting the server fulfill its role.
For example, in most environments clients have no need to remotely mount
the NFS server’s root filesystem.
Define which clients may mount which filesystems and directories in
/etc/exports. This file takes a separate line for each disk device on the server
and each client or group of clients that access that device. Each line has up to
three parts:
Directories or partitions to be exported (mandatory)
Options on that export
Clients that can connect
Each combination of clients and a disk device can only have one line in
the exports file. This means that if /usr/ports and /usr/home are on the same
partition, and you want to export both of them to a particular client, they
must both appear in the same line. You cannot export /usr/ports and /usr/home
to one client with different permissions. You don’t have to export the entire
disk device, mind you; you can export a single directory within a partition.
This directory cannot contain either symlinks or double or single dots.
Of the three parts of the /etc/exports entry, only the directory is mandatory.
If I wanted to export my home directory to every host on the Internet, I could
use an /etc/exports line consisting entirely of this:
/home/mwlucas
We show no options and no host restrictions. This would be foolish,
of course, but I could do it.3
After editing the exports file, tell mountd to reread it:
# /etc/rc.d/mountd restart
mountd(8) logs any problems in /var/log/messages. The log messages
are generally enigmatic: While mountd(8) informs you that a line is bad, it
generally doesn’t say why. The most common errors I experience involve
symlinks.
Enabling the NFS Client
Configuring the client is much simpler. In /etc/rc.conf, put:
nfsclient="YES"
Then, reboot or run /etc/rc.d/nfsclient start. Either will enable NFS
client functions.
Now we can mount directories or filesystems exported by NFS servers.
Instead of using a device name, use the NFS server’s host name and the
directory you want to mount. For example, to mount the directory /home/ mwlucas from my server sardines onto the directory /mnt, I would run:
The NFS-mounted directory shows up as a normal partition, and I can
read and write files on it as I please. Well, maybe not entirely as I please . . .
NFS and Users
File ownership and permissions are tied to UID numbers. NFS uses UID to
identify the owner. For example, on my laptop the user mwlucas has the UID
of 1001. On the NFS server, mwlucas also has the UID 1001. This makes my life
easy, as I don’t have to worry too much about file ownership; I have the same
privileges on the server as on my laptop. This can be a problem on a large
network, where users have root on their own machines. The best way around
this is to create a central repository of authorized users via Kerberos. On a
small network or on a network with a limited number of NFS users, this usually
isn’t a problem; you can synchronize /etc/master.passwd on your systems or just
assign the same UID to each user on each system.
The root user is handled slightly differently, however. An NFS server
doesn’t trust root on other machines to execute commands as root on the
server. After all, if an intruder breaks into an NFS client you don’t want the
server to automatically go down with it. You can map requests from root to
any other username. For example, you might say that all requests from root
on a client will run as the user nfsroot on the server. With careful use of
groups, you could allow this nfsroot user to have limited file access. Use the
-maproot option to map root to another user. Here, we map UID 0 (root) on
the client to UID 5000 on the server:
/usr/home/mwlucas -maproot=5000
If you really want the root user on the client to have root privileges on
the server, you can use -maproot to map root to UID 0. This might be suitable
on your home network or on a test system.
If you do not use a maproot statement, the NFS maps a remote root account
to nobody:nobody by default.
Don’t forget to restart mountd(8) after editing the exports file.
Exporting Multiple Directories
Many directories under /usr would make sensible exports. Good candidates
include /usr/src, /usr/obj, and /usr/ports/distfiles. List all directories of the
same partition on the same line in /etc/exports, right after the first exported
directory, separated by spaces. My /etc/exports now looks like this:
There are no identifiers, separators, or delimiters between the parts of
the line. Yes, it would be easier to read if we could put each shared directory
on its own line, but we can’t; they’re all on the same partition. The FreeBSD
team could rewrite this so that it had more structure, but then FreeBSD’s
/etc/exports would be incompatible with that from any other Unix.
As with many other configuration files, you can use a backslash to break
a single line of configuration into multiple lines. You might find the above
configuration more readable as:
Restricting Clients
To allow only particular clients to access an NFS export, list them at the end
of the /etc/exports entry. Here, we restrict our share above to one IP address:
This lets any client with an IP address beginning in 192.168.0 access your
NFS server. I use a setup much like this to upgrade clients quickly. I build a
new world and kernel on the NFS server, then let the clients mount those
partitions and install the binaries over NFS.
Combinations of Clients and Exports
Each line in /etc/exports specifies exports from one partition to one host or set
of hosts. Different hosts can have entirely different export statements.
Here, I’ve exported several subdirectories of /usr to the NFS client at
192.168.1.200. The NFS client at 192.168.1.201 gets to mount the whole of
/usr, and may even do so as root.
NFS Performance and Options
FreeBSD uses conservative NFS defaults, so that it can work well with any other
Unix-like operating system. If you’re working in a pure FreeBSD environment
or if your environment only contains higher-end Unix systems, you can
improve NFS performance with mount options.
First of all, NFS defaults to running over UDP. The tcp or -T option tells
the client to request a mount over TCP.
Programs expect the filesystem to not disappear, but when you’re using
NFS it’s possible that the server will vanish from the network. This makes
programs on the client trying to access the NFS filesystem hang forever. By
making your NFS mount interruptible, you will be able to interrupt processes
hung on unavailable NFS mount with CTRL-C. Set interruptibility with intr.
FreeBSD can tell clients if and when a filesystem is no longer accessible.
Programs will fail when trying to access the filesystem, instead of hanging
forever.
Finally, you can set the size of read and write requests. The defaults are
well-suited to networks of the early 1990s, but you can set the read and write
size to more modern values with the -r and -w options. I find that 32768 is a
good value for both. So, putting this all together, I could have my client
mount an NFS file system like this:
# mount -o tcp,intr,soft,-w=32768,-r=32768 server:/usr/home/mwlucas /mnt
This general NFS configuration gives me good throughput speed on a
local network, limited only by hardware quality.
While NFS is pretty straightforward for simple uses, you can spend many
hours adjusting, tuning, and enhancing it. If you wish to build a complicated
NFS environment, don’t rely entirely on this brief introduction but spend
time with a good book on the subject.
FREEBSD AND CIFS
If you’re on a typical office network, the standard network file sharing
protocol is Microsoft’s Common Internet File Sharing, or CIFS. (CIFS was
once known as Server Message Block, or SMB.) This is the "Network
Neighborhood" that Windows users can access. While originally provided
only by Microsoft Windows systems, this protocol has become something of
a standard. Thankfully, today there’s an open source CIFS file sharing server
called Samba. Many commercial products provide services via this protocol.
FreeBSD includes kernel modules to support the filesystem and programs to
find, mount, and use CIFS shares.
Prerequisites
Before you begin working with Microsoft file shares, gather the following
information about your Windows network:
Workgroup or Windows domain name
Valid Windows username and password
IP address of the Windows DNS server
Kernel Support
FreeBSD uses several kernel modules to support CIFS. The smbfs.ko module
supports basic CIFS operations. The libmchain.ko and libiconv.ko modules provide
supporting functions and load automatically when you load smbfs.ko. You
can compile these statically in your kernel as:
Of course, you can load these at boot time with the appropriate entries
in /boot/loader.conf.
Configuring CIFS
CIFS relies on a configuration file, either $HOME/.nsmbrc or /etc/nsmb.conf.
All settings in /etc/nsmb.conf override the settings in user home directories.
The configuration file is divided into sections by labels in square brackets.
For example, settings that apply to every CIFS connection are in the [default]
section. Create your own sections to specify servers, users, and shares, in one
of the following formats:
Information that applies to an entire server goes into a section named
after the server. Information that applies to a specific user is kept in a
username section, and information that applies to only a single share is
kept in a section that includes the share name. You can lump the information
for all the shares under a plain [servername] entry if you don’t have more
specific per-user or per-share information.
Configuration entries use the values from the CIFS system—for example,
my Windows username is lucas_m, but my FreeBSD username is mwlucas, so
I use lucas_m in nsmb.conf.
nsmb.conf Keywords
Specify a nsmb.conf configuration with keywords and values under the
appropriate section. For example, servers have IP addresses and users don’t,
so you would only use an IP address assignment in the server section. To use
a keyword, assign a value with an equal sign, as in keyword=value. Here are
the common keywords; for a full list, see nsmb.conf(5).
workgroup=string
The workgroup keyword specifies the name of the Windows domain or workgroup
you want to access. This is commonly a default setting used for all
servers.
addr=a.b.c.d
The addr keyword sets the IP address of a CIFS server. This keyword can only
appear under a plain [servername] label.
nbns=a.b.c.d
The nbns keyword sets the IP address of a NetBIOS (WINS) nameserver. You
can put this line in the default section or under a particular server. If you
have Active Directory (which is based on DNS), you can use DNS host names.
Adding a WINS server won’t hurt your configuration, however, and helps in
testing basic CIFS setup.
password=string
The password keyword sets a clear-text password for a user or a share. If you
must store passwords in /etc/nsmb.conf, be absolutely certain that only root
can read the file. Storing a password in $HOME/.nsmbrc is a bad idea on a
multi-user system.
You can scramble your Windows password with smbutil crypt, generating
a string that you can use for this keyword. The scrambled string has double
dollar signs ($$) in front of it. While this helps prevent someone accidentally
discovering the password, a malicious user can unscramble it easily.
CIFS Name Resolution
Let’s build a basic nsmb.conf file. As an absolute minimum, we first need to
find hosts, which means we need a workgroup name. We’ll set the domain
controller as the WINS server. I also have a user set up on the Windows-based
servers to share files, so I’m going to use that as a default in nsmb.conf.
Armed with this information, we can perform basic SMB name queries.
# smbutil lookup ntserv1
Got response from 192.168.1.66
IP address of ntserv1: 192.168.1.4
If this works, you have basic CIFS functionality.
Other smbutil(1) Functions
Before you can mount a filesystem from a Windows host, you must log into
the host. Only root can perform this operation.
# smbutil login //unix@ntserv1
Password:
So, our configuration is correct. Let’s see what resources this server
offers with smbutil’s view command.
# smbutil view //unix@ntserv1
Password:
Share Type Comment
IPC$ pipe Remote IPC
ADMIN$ disk Remote Admin
C$ disk Default share
unix disk
4 shares listed from 4 available
You’ll get a list of every shared resource on the CIFS server. Now,
assuming you’re finished, log out of the server.
# smbutil logout //unix@ntserv1
Mounting a Share
Now that you’ve finished investigating, let’s actually mount a share with
mount_smbfs(8). The syntax is as follows:
mount(8) and df(1) show this share attached to your system, and you
can access documents on this server just as you could any other filesystem.
Other mount_smbfs Options
mount_smbfs includes several options to tweak the behavior of mounted
CIFS filesystems. Use the -f option to choose a different file permission
mode and the -d option to choose a different directory permission mode.
For example, to set a mount so that only I could access the contents of the
directory, I would use mount_smbfs -d 700. This would make the FreeBSD
permissions far more stringent than the Windows privileges, but that’s
perfectly all right with me. I can change the owner of the files with the -u
option, and the group with the -g option.
Microsoft filesystems are case-insensitive, but Unix-like operating systems
are case sensitive. CIFS defaults to leaving the case as it finds it, but that may
not be desirable. The -c flag makes mount_smbfs(8) change the case on the
filesystem: -c l changes everything to lowercase and -c u changes everything
to uppercase.
Sample nsmb.conf Entries
Here are samples of nsmb.conf entries for different situations. They all assume
they’re part of a configuration where you’ve already defined a workgroup,
NetBIOS nameserver, and a username with privileges to access the CIFS
shares.
Unique Password on a Standalone System
You would use something like the following if you have a machine named
desktop with a password-protected share. Many Windows 9x systems have this
sort of password-protection feature.
[desktop:shareusername]
password=$$1789324874ea87
Accessing a Second Domain
In this example, we’re accessing a second domain, named development.
This domain has a username and password different from those at our
default domain.
Ownership of files between Unix-like and Windows systems can be problematic.
For one thing, your FreeBSD usernames probably won’t map to Windows
usernames, and Unix has a very different permissions scheme compared to
Windows.
Since you’re using a single Windows username to access the share, you
have whatever access that account has to the Windows resources, but you must
assign the proper FreeBSD permissions for that mounted share. By default,
mount_smbfs(8) assigns the new share the same permissions as the mount
point. In our earlier example, the directory /home/mwlucas/smbmount is owned
by the user mwlucas and has permissions of 755. These permissions say that
mwlucas can edit what’s in this directory, but nobody else can. Even though
FreeBSD says that this user can edit those files, Windows might still not let
that particular user edit the files it’s sharing out.
SERVING CIFS SHARES
Just as FreeBSD can access CIFS shares, it can also serve them to CIFS clients
with Samba. You can find Samba in /usr/ports/net/samba3. You’ll find the
Samba website at http://www.samba.org, along with many useful tutorials.
Serving CIFS shares from FreeBSD is much more complicated than accessing
them, so we’ll end our discussion here before this book grows even thicker.
devfs(5) is a dynamic filesystem for managing device nodes. Remember, in a
Unix-like operating system everything is a file. This includes physical hardware.
Every device on the system has a device node under /dev.
Once upon a time, the system administrator was responsible for making
these device node files. Lucky sysadmins managed an operating system that
came with a shell script to handle device node creation and permissions. If the
OS authors had not provided such a shell script, or if the server had unusual
hardware not included in that shell script, the sysadmin had to create the node
with black magic and mknod(8). If any little thing went wrong, the device
would not work. The other option was to ship the operating system with
device nodes for every piece of hardware imaginable. System administrators
could be confident—well, mostly confident—that the desired device nodes
were available, somewhere, buried within the thousands of files under /dev.
Of course, the kernel knows exactly what characteristics each device node
should have. With devfs(5), FreeBSD simply asks the kernel what device nodes
the kernel thinks the system should have and provides exactly those—and no
more. This works well for most people. You and I are not "most people,"
however. We expect odd things from our computers. Perhaps we need to
make device nodes available under different names, or change device node
ownership, or configure our hardware uniquely. FreeBSD breaks the problem
of device node management into three pieces: configuring devices present at
boot, global availability and permissions, and configuring devices that appear
dynamically after boot with devd(8).
DEVICE MANAGEMENT AND SERVERS
For the most part, device node management on servers works without any adjustment
or intervention. The place I most often need to muck with device nodes is on laptops
and the occasional workstation. FreeBSD’s device node management tools are very
powerful and flexible, and incude support for things I wouldn’t expect to use in a
century. We’ll ony touch upon the basics. Don’t think that you must master devfs(5) to get your server running well!
devfs at Boot: devfs.conf
The big problem sysadmins have with a dynamic devfs is that any changes
made to it disappear on reboot. When device nodes were permanent files on
disk, the sysadmin could symlink to those nodes or change their permissions
without worrying that his changes would vanish. With an automated, dynamic
device filesystem, this assurance disappears. (Of course, you no longer have
to worry about occult mknod(8) commands either, so you’re better off in the
long run.) The device node changes could include, for example:
Making device nodes available under different names
Changing ownership of device nodes
Concealing device nodes from users
At boot time, devfs(8) creates device nodes in accordance with the rules
in /etc/devfs.conf.
devfs.conf
The /etc/devfs.conf file lets you create links, change ownership, and set permissions
for devices available at boot. Each rule has the following format:
action realdevice desiredvalue
The valid actions are link (create a link), perm (set permissions), and own
(set owner). The realdevice entry is a preexisting device node, while the last
setting is your desired value. For example, here we create a new name for a
device node:
We want a symbolic link to the device node /dev/acd0 (an ATAPI CD
drive), and we want this link to be named /dev/cdrom. If we reboot with this
entry in /etc/devfs.conf, our CD device at /dev/acd0 also appears as /dev/cdrom,
as many desktop multimedia programs expect.
To change the permissions of a device node, give the desired permissions
in octal form as the desired value:
perm acd0 666
Here, we set the permissions on /dev/acd0 (our CD device, again) so that
any system user can read or write to the device. Remember, changing the
permissions on the /dev/cdrom link won’t change the permissions on the
device node, just the symlink.
Finally, we can also change the ownership of a device. Changing a device
node’s owner usually indicates that you’re solving a problem the wrong way
and that you may need to stop and think. FreeBSD happily lets you mess up
your system if you insist, however. Here, we let a particular user have absolute
control of the disk device /dev/da20:
own da20 mwlucas:mwlucas
This might not have the desired effect, however, as some programs still
think that you must be root to carry out operations on devices. I’ve seen
more than one piece of software shut itself down if it’s not run by root,
without even trying to access its device nodes. Changing the device node
permissions won’t stop those programs’ complaints when they are run by a
regular user.
Configuration with devfs.conf(5) solves many problems, but not all. If
you want a device node to simply be invisible and inaccessible, you must use
devfs rules.
Global devfs Rules
Every devfs(5) instance behaves according to the rules defined in devfs.rules.
The devfs rules apply to both devices present at boot and devices that appear
and disappear dynamically. Rules allow you to set ownership and permissions
on device nodes and make device nodes visible or invisible. You cannot create
symlinks to device nodes with devfs rules.
Similar to /etc/rc.conf and /etc/defaults/rc.conf, FreeBSD uses /etc/devfs.rules
and /etc/defaults/devfs.rules. Create an /etc/defvs.rules for your custom rules and
leave the entries in the defaults file alone.
devfs Ruleset Format
Each set of devfs rules starts with a name and a ruleset number between
square brackets. For example, here are a few basic devfs rules from the
default configuration:
The first set of rules is called devf s_hide_all and is ruleset number 1
This ruleset contains only one rule .
Ruleset Content
All devfs rules (in files) begin with the word add, to add a rule to the ruleset.
You then have either a path keyword and a regex of device names, or a type
keyword and a device type. At the end of the rule, you have an action, or a
command to perform. Here’s an example of a devfs rule:
add path da* user mwlucas
This rule assigns all device nodes with a node name beginning with da to
the ownership of mwlucas. On a multi-user system, or a system with SCSI
hard drives, this would be a bad idea. On a laptop, where the only device
nodes beginning with da are USB storage devices, it’s not such a bad idea.
Devices specified by path use standard shell regular expressions. If you
want to match a variety of devices, use an asterisk as a wildcard. For example,
path ad1s1 matches exactly the device /dev/ad1s1, but path ad*s* matches
every device node with a name beginning with ad, a character, the letter s,
and possibly more characters. You could tell exactly what devices are matched
by a wildcard by using it at the command line.
# ls /dev/ad*s*
This lists all slices and partitions on your ATA hard drives, but not the
devices for the entire drive.
The type keyword indicates that you want the rule to apply to all devices
of a given type. Valid keywords are disk (disk devices), mem (memory devices),
tape (tape devices), and tty (terminal devices, including pseudoterminals).
The type keyword is rarely used exactly because it’s so sweeping.
If you include neither a path nor a type, devfs applies the action at the
end of the rule to all device nodes. In almost all cases, this is undesirable.
The ruleset action can be any one of group, user, mode, hide, and unhide.
The group action lets you set the group owner of the device, given as an
additional argument. Similarly, the user action assigns the device owner.
Here, we set the ownership of da disks to the username desktop and the
group usb:
add path da* user desktop
add path da* group usb
The mode action lets you assign permissions to the device in standard
octal form:
add path da* mode 664
The hide keyword lets you make device nodes disappear, and unhide
makes them reappear. Since no program can use a device node if the device
is invisible, this is of limited utility except when the system uses jail(8). We’ll
look at that specific use of hide and unhide in the next chapter.
Once you have a set of devfs rules you like, enable them at boot in
/etc/rc.conf. Here, we activate the devfs ruleset named laptoprules:
devfs_system_rulesets="laptoprules"
Remember, devfs rules apply to the devices in the system at boot and
the devices configured dynamically after startup. To finish up, let’s look at
dynamic devices.
Dynamic Device Management with devd(8)
Hot-swappable hardware is much more common now than it was even ten
years ago. In the last century, laptop network cards were considered cuttingedge.
While you might drop a new CD into the workstation’s cup holder, you
wouldn’t hot-plug a whole CD drive into your desktop. Today, that’s entirely
different. Flash drives are essentially USB-based hard drives that you can
attach and detach at will, and other USB hardware lets you add keyboards,
mice, and even network cards on a whim.
FreeBSD’s devfs dynamically creates new device nodes when this hardware
is plugged in and erases the nodes when the hardware is removed, making
using these dynamic devices much simpler. devd(8) takes this a step further
by letting you run userland programs when hardware appears and disappears.
devd Configuration
devd(8) reads its configuration from /etc/devd.conf and any file under
/usr/local/etc/devd/. I recommend placing your local rules in /usr/local/etc/ devd/devd.conf to simplify upgrades. You could also add different rules files
for different types of devices, if you find your devd(8) configuration
becoming very complicated. You’ll find four types of devd(8) rules: attach,
detach, nomatch, and notify.
attach rules are triggered when matching hardware is attached to the
system. When you plug in a network card, an attach rule configures the card
with an IP address and brings up the network.
detach rules trigger when matching hardware is removed from the system.
detach rules are uncommon, as the kernel automatically marks resources
unavailable when the underlying hardware disappears, but you might find
uses for them.
The nomatch rules triggers when new hardware is installed but not
attached to a device driver. These devices do not have device drivers in the
current kernel.
devd(8) applies notify rules when the kernel sends a matching event notice
to userland. For example, the console message that a network interface has
come up is a notify event. Notifications generally appear on the console or in
/var/log/messages.
devd(8) rules also have priority, with 0 being the lowest. Only the highest
matching rule is processed, while lower-priority matching rules are skipped.
Here’s a sample devd(8) rule:
This is a notify rule, which means it activates when the kernel sends a
message to userland. As a priority 0 rule, this rule can only be triggered
if no rule of higher-priority matches the criteria we specify. This rule only
triggers if the notification is on the network system IFNET (network), and
only if the notification type is ATTACH —in other words, when a network
interface comes up. Under those circumstances, devd(8) takes action and
runs a command to configure the network interface .
devd(8) supports many options to handle all sorts of different situations.
If you want to automatically mount a particular USB flash disk on a certain
mount point, you can do that by checking the serial number of every USB
device you put in. If you want to configure Intel network cards differently
than 3Com network cards, you can do that too. We’ll do enough with devd(8)
to introduce you to its abilities, mainly through examples, but we won’t delve
deeply into it.
devd(8) Example: Laptops
I use my laptop both at work and at home. At work I use a wired connection,
while at home I use wireless. Both require very particular setups, different DNS
servers, and different configurations all around. I could cheat by renumbering
my home network to match my work network, but experience tells me that my
home network will last much longer than my attachment to any one job.
(Maybe I’m wrong.4) I want the laptop to configure itself for home when I
plug in my wireless card. I want the laptop to configure itself for work when
I plug in the CAT5 cable to the integrated network interface.
If a wired interface is configured to use DHCP, plugging in the cable
tells FreeBSD to start dhclient(8) and configure the network. When I plug
in a wireless card, FreeBSD checks for a configuration and tries to start the
network. Here’s my wireless configuration from /etc/rc.conf (this is all one
line in the configuration, but it is broken to fit in this book):
When I insert my wireless card, the kernel attaches the card to the driver
wi0. This is an attach event, and devd(8) searches its configuration for a
corresponding rule. The following entry in /etc/devd.conf matches:
We inserted a card into the laptop, and FreeBSD attached the wi(4)
driver to it. This is an attach event. This rule has a priority of 0 , so any
other matching rule will run before this default rule. Anything with a media
type of 802.11 (wireless) matches this rule. When an attach event matches
this rule, FreeBSD runs a command to configure the network. I could run
a custom script instead of using the built-in FreeBSD support, but why bother
when the default configuration does everything I need?
Unlike the wireless I use at home, the Ethernet interface I use at work is
always attached to my system. The interface might not be plugged into a
network, but the card itself is always attached. I don’t want to configure this
interface every time the system boots, because if the interface isn’t plugged
in I’ll have a long delay while my laptop’s SSH daemon and other services
time out on DNS queries. At work I have a variety of NFS mounts, as well as
custom client/server settings not available from the DHCP server.
This means that I need to run a custom shell script to configure my
network for work, but only when the network cable is plugged in. I want
devd to watch for a notification that the interface has come up and then
run my custom shell script. I’ve written the custom entry below and placed
it in /usr/local/etc/devd/devd.conf:
This is a notification rule, which means it triggers when the kernel
sends a matching notification message to the system. It also has a priority of
10 , so it runs before any of FreeBSD’s default rules. This rule triggers on
the network system, when a link comes up (i.e., when we plug in a
network cable), if the link is Ethernet . When all of these conditions are
met, FreeBSD runs a shell script in my home directory.
Note that this rule has a commented-out line . When I said I wrote
this rule, I lied. I actually copied the default entry from /etc/devd.conf and
modified it slightly. FreeBSD already has rules for handling network interfaces
coming up, but I wanted to do something a little different. Instead of coming
up with all these conditions myself, I found a entry that was almost right and
modified it. I suggest you do the same. Just be sure to give your customized
rule a higher priority than the default rule, so FreeBSD uses your rule instead
of its own.
Another devd Example: Flash Drives
Copying an entry is cheating, I hear you cry. Well, let’s try an example where
FreeBSD doesn’t have any infrastructure in place. On my laptop, I want any
USB storage mounted on /media automatically. The first USB storage device
plugged into a laptop shows up in FreeBSD as /dev/da0, but the device name is
umass0. (If you already have other USB or SCSI devices, these numbers will
differ for you.) Generally speaking, all flash media is formatted with the FAT32
fileystem, so you would use mount -t msdosfs to mount it.
When the device is plugged in, FreeBSD attaches it to the kernel, so we
use an attach rule:
I assign this rule a priority of 10, so it overrides any new priority 0
functions FreeBSD might install during an upgrade. (If FreeBSD grows the
ability to do this automatically, I’ll probably use that instead, but I don’t want
an upgrade to change my system behavior unless I know about it.) Here, we
match on the device name . When the device appears, a shell script in my
directory runs.
Why not just run the mount(8) command? USB devices need a moment
or two to warm up and stabilize before they can be accessed. Also, some USB
flash drives need to be poked before they really start to work. The shell script
I use here is terribly simpleminded, but it suffices:
While this handles mounting the device for me, devd(8) won’t unmount
the device. FreeBSD expects the sysadmin to unmount filesystems before
removing the underlying devices. It’s no different from unmounting a CD
or floppy disk before ejecting it.
While devd(8) has many more advanced features, these two examples
cover all the features I’ve needed or wanted to use in several years. Please
read the manual page if you seek further enlightenment. Now that you have
a little bit too much understanding of FreeBSD filesystems, let’s look at its
more advanced security features.
Why is there no safeguard against shooting yourself in the foot like this? Well, Unix feels that
anyone dumb enough to do this doesn’t deserve to be its friend. Various people keep trying to
put Unix in therapy for this type of antisocial behavior, but it just isn’t interested.
It would be nice, some day, to have employment that didn’t end with four corporate security
gorillas dragging me to the door in chains, with my new ex-boss screeching in the background
about federal regulators, crème brûlée, and caffeinated lemurs. I’m certain this is just coincidence,
mind you, as nobody’s ever pressed charges.
WinConnections Conference Fall 2008 Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).
Master SharePoint with 3 eLearning Seminars Learn how to build a better SharePoint infrastructure and enable powerful collaboration with MVPs Dan Holme and Michael Noel. Register today!
SharePointConnections Conference Fall 2008 Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).
VMworld 2008 - Sign Up Today! Join your peers on September 15-18 at The Venetian Hotel in Las Vegas as VMware hosts VMworld 2008, the leading Virtualization event.
Microsoft® Tech•Ed EMEA 2008 IT Professionals Advance your thinking with new ideas and practical real-world solutions at Microsoft’s FIVE day technical infrastructure conference 3-7 Nov., 2008. Register before 26 September 2008 to save €300.
Order Your Fundamentals CD Today! Gain an introduction to Exchange, learn server security requirements, and understand how unified communications can play a role in your messaging strategies with this free Exchange CD.
Are You Really Compliant with Software Regulations? View this web seminar that will help you with compliance best practices and check out a management solution to assure that you won’t be in jeopardy of an audit.
Virtualization Congress Oct. 14-16 in London Don't miss Virtualization Congress, the premiere EMEA conference dedicated to hardware, OS and application virtualization. Oct. 14-16 in London.