Heinlein fans will recognize the word grok as the Martian word for “to be one with” or “thorough understanding.” Indeed, you will sometimes feel like a stranger in a strange land when learning Unix. As any Unix guru can attest, however, the rewards far outweigh the initial learning curve.
This final chapter is a hodgepodge of useful and sometimes amusing tidbits. A sure sign you’re on the right road to grokking BSD is when you’re able to see both the usefulness and the quirky humor that is inherent in all Unix systems.
Make the most of your available resources.
Unless you’ve achieved Unix guru status, you probably find yourself asking “how did he know that?” whenever you’re around other Unix users or read a really cool snippet in a book. Here’s a little secret: he probably had to look it up. As I tell my students, “No one knows everything. Make sure the one thing you do know is where to go to get the information you need.”
If you’re using FreeBSD, there is no shortage of well-written documentation. If you haven’t already, bookmark the FreeBSD Documentation page at http://www.freebsd.org/docs.
There you’ll find hyperlinks to the four handbooks, the FAQ, how-to articles, online manpages, as well as other sources of information. There’s a very good chance that someone else has already documented what you want to do.
Online resources are great, but what if you don’t always have
access to an Internet connection? If you installed the doc
distribution, you already have most of
those resources on your hard drive. You’ll find the handbooks, FAQ,
and articles in /usr/share/doc.
That directory contains symlinks so you can quickly navigate to the
desired resource.
If you haven’t installed the doc
directory structure, you can do so
through /stand/sysinstall
. Enter
Configuration
, then Distributions
, and use your spacebar to
select doc
.
The online resources receive daily updates, so be sure to update
your docs when you use cvsup
. Make
sure your cvsup file includes
this line:
doc-all tag=.
If you’re not using cvsup [Hack #80] yet, you have no idea what you’re missing!
As cvsup
retrieves the latest
docs, it will write them to /usr/doc. This will
not overwrite or update existing files in
/usr/share/doc. Also, if you’ve
ever poked about /usr/doc, you
probably noticed that the resources themselves are written in SGML,
making them a bit hard to read (unless you enjoy wading through
tags).
How do you merge in those new changes? It’s going to require a
conversion of SGML to HTML. To achieve that, first install the
docproj-nojadetex
port:
#cd /usr/ports/textproc/docproj-nojadetex
#make install clean
Then:
#cd /usr/doc
#make install clean
This will merge all of the changes into the HTML files in
/usr/share/doc. If you add this
step to your cvsup
routine, your
offline resources will always be up-to-date.
Have you ever read a manpage and been unclear on how a certain switch worked? Perhaps you thought you understood the syntax until you tried it out and only managed to produce syntax error messages? Even more maddeningly, you might scour the Internet for concrete examples only to find endless links to the same manpage!
When this happens to me, I consider the program’s source as a possible answer. If you’re thinking, “I’m not a programmer; I couldn’t read source code if my life depended on it,” don’t just skip to the next hack. You can still read comments, and most source in the FreeBSD core is very well commented.
Here’s an example. I was reading through man mac_portacl
, which indicates that the
rule MIB takes this syntax:
idtype:id:protocol:port[,idtype:id:protocol:port,...]
but didn’t give a specific example of a working rule. Since this particular MAC policy doesn’t do anything until you successfully create a rule, I was looking for a more concrete example of an effective rule. And, since this module is fairly new, there weren’t any tutorials or how-tos on the Internet. So, before hitting the mailing lists, I took a peek at the source.
To locate any C source file, use the locate
command. Pass it the name of what you’re looking for,
followed by a .c
. For
example:
% locate mac_portacl.c
/usr/src/sys/security/mac_portacl/mac_portacl.c
You must have src
installed
in order for this to work, and, as indicated, it will only find source
code written in C. Happily, that’s most of the FreeBSD core. You can
use /sys/sysinstall
to install all
of the src
distributions. If disk
space is an issue or it’s not appropriate to install source on the
system you’re logged into, you can read the source online at http://minnie.tuhs.org/FreeBSD-srctree/FreeBSD.html.
If you have src
installed but
don’t see any results or do receive an error message that your
database is too small, update the database and try again:
%su
Password: #/usr/libexec/locate.updatedb
>>> WARNING >>> Executing updatedb as root. This WILL reveal all filenames >>> on your machine to all login users, which is a security risk. #exit
Once you’ve located the source file, skim through its comments:
% grep '*' /usr/src/sys/security/mac_portacl/mac_portacl.c | tail +30
Here, I told grep
to search
for an asterisk (*
), since C
comments always include one. If you forget to enclose the asterisk
within single quotes (''), you won’t receive any results, as it is
also a shell wildcard. You may want to adjust tail +30
for your own purposes. Source code
begins with anywhere from 25 to 40 lines of copyright and licensing
comments. Here I’ve told tail
to
ignore the first (+
) 30 lines of
comments.
In this particular case, the comments included the example I hoped for:
* # sysctl security.mac.portacl.rules="uid:425:tcp:80,uid:425:tcp:79" * * This ruleset, for example, permits uid 425 to bind TCP ports 80 (http) * and 79 (finger). User names and group names can't be used directly * because the kernel only knows about uids and gids.
Your mileage will vary, but source is definitely another resource at your disposal.
man hier
(includes a
description of the contents of /usr/share/doc/)
man tail
As a Unix administrator, the one word of sage advice you can give to any user that is guaranteed to solve any problem is RTFM.
What’s an administrator to do when informed by a user that there is no manpage to read? Perhaps the application in question is a custom application or script, or perhaps it’s a third-party program that didn’t come with a manpage. Why not create the missing manual yourself?
Creating a manpage isn’t all that difficult. After all, a
manpage is simply a text file—more specifically, a gzip
ped text file sprinkled with groff
macros. (I’m quite sure groff
gets its name from the choking sound
you make as you try to decipher its manpage.) For
man
to do its magic, which starts
with being able to find the page, the manpage
must live in a directory manpath
can see.
Not surprisingly, manpath
’s
configuration file, /etc/manpath.config, contains those
paths:
% grep MAP /etc/manpath.config
# MANPATH_MAP path_element manpath_element
MANPATH_MAP /bin /usr/share/man
MANPATH_MAP /usr/bin /usr/share/man
MANPATH_MAP /usr/local/bin /usr/local/man
MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
Basically, manpages to programs that come with the system live
in /usr/share/man, third-party
applications use /usr/local/man,
and X applications use /usr/X11R6/man. If you ls
any of these directories, you’ll find
directory names that go from man1
to man9. If you’re rusty on the
function of each manpage section, run:
% whatis intro
intro(1) - introduction to general commands (tools and
utilities)
intro(2) - introduction to system calls and error numbers
intro(3) - introduction to the C libraries
intro(4) - introduction to devices and device drivers
intro(5) - introduction to file formats
intro(6) - introduction to games
intro(7) - miscellaneous information pages
intro(8) - introduction to system maintenance and
operation commands
intro(9) - introduction to system kernel interfaces
To read a specific section, specify the number between the
command and the page, as in man 7
foo
.
You can whip up a nicely formatted manpage by knowing only three
groff
commands, as shown in Table 9-1.
The easiest way to convince yourself of this is to take a few
minutes to type out the following custom manpage. When you’re
finished, save it as /usr/local/man/man1/boss.1 (as the root
user) and view it with man boss
. That way, you’ll be able to
compare those formatting sequences with how the results are displayed
on your screen.
." Manpage for boss. ." Contact [email protected] to correct errors or omissions. .TH man 1 "04 January 2004" "1.0" "boss man page" .SH NAME boss - man page for boss .SH SYNOPSIS boss .SH DESCRIPTION The boss is an ornery creature that can be appeased with doughnuts and the occasional afternoon off for golf. .SH OPTIONS The boss does not take any options. .SH SEE ALSO doughnut(1), golf(8) .SH BUGS No known bugs at this time. .SH AUTHOR Dru Lavigne ([email protected])
If you take the time to view this listing, you’ll find it looks like any manpage. In fact, it’s an excellent idea to take a look at several manpages before you create your own. This will give you an idea of how you’d like your custom page to appear.
Notice first that the lines that began with .
" don’t appear anywhere in the formatted
manpage, as they are comments. The information in the title (.TH
) line appears at the very top and bottom
of the manpage. The .SH
lines
appear nicely bolded, and the following lines are indented for you.
Remember that .SH NAME
is
mandatory, but you can create as many .SH
sections as you wish.
As you read other manpages, you’ll see that SYNOPSIS
, DESCRIPTION
, OPTIONS
, EXAMPLES
, DIAGNOSTICS
, ENVIRONMENT
, SEE
ALSO
, HISTORY
, and
BUGS
are quite common. You’ll also
get an idea of what type of text belongs in each section.
If you want to include fancier formatting in your manpage, find an existing manpage that has the desired
format. Then, instead of opening the manpage with man
, send it to zmore
. (Remember, you won’t be able to read
gzip
ped manpages directly with
more
.)
For example, if I want to include switches, I’d borrow from a manpage with switches.
ls
springs to mind. So I’ll read
through:
% zmore /usr/share/man/man1/ls.1.gz
and compare it to man ls
. In
this manpage, the switches occur in the DESCRIPTION
section and the first switch is
-A
. The switch itself is in bold
text and the switch description is indented with the characters . and
.
. covered over with white. The
formatting sequences to achieve this are:
.BL -tag -width indent .It Fl A List all entries except for .Pa &. and .Pa .. .
If you’re curious as to the exact meaning of each formatting
sequence, you’ll find them scattered throughout man 7 groff
. If you don’t have the time to
be curious, simply find the section that does what you want and add it
to your own manpage. Save your results, then see if it worked by
sending your custom manpage to man
.
It’s often desirable to print certain manpages. If you’ve ever tried sending a manpage
directly to a printer, you probably found that the results weren’t
what you were expecting. However, you can use groff
to convert the manpage to something
more printer-friendly. PostScript is usually your best bet, and you’re
in luck, as groff
knows how to
convert to PostScript.
First, it’s not a bad idea to get the exact location of the
source of the manpage. Continuing with ls
as an example:
% man -w ls
/usr/share/man/cat1/ls.1.gz (source: /usr/share/man/man1/ls.1.gz)
Note that you’re interested in the source, not in the location
that includes the word cat
.
Once you know the location, use zcat
to open the compressed file, pipe the
results to groff
, and redirect the
groff
output to a PostScript
file:
#zcat /usr/share/man/man1/ls.1.gz | groff > ls.ps
#file ls.ps
ls.ps: PostScript document text conforming at level 3.0
Note that the default invocation of groff
assumes that you wish to convert a
manpage to PostScript, so you need no additional switches.
If you’d like to publish your manpages on a local web site,
groff
can also convert to HTML—see
man 1 groff
for details.
If you prefer to convert to PDF, consider installing GNU
GhostScript from your ports or packages collection. Once installed,
read man 1 gs
for more
details.
Now that you know how to create your own manpages, you’ll want to know how to get the most out of your manpage viewing.
Since most documentation on Unix systems lives within manpages,
it pays to know how to get the most out of your manpage-reading
experience. How do you make sure you’re aware of all of the manpages
installed on a system? How do you zero in on the information you need,
without having to read an entire manpage? Yes, it’s a great experience
to read all of man tcsh
at least once
in your life, but you don’t want to do that when you’re only interested
in a certain shell variable.
You may have noticed that, by default, whatis [Hack #13] doesn’t find custom manpages or those installed by third-party applications. Not only is this inconvenient, but it can also prevent your users from getting the most out of the applications installed on a system.
Remember /etc/manpath.config from [Hack #90] ?
% grep MAP /etc/manpath.config
# MANPATH_MAP path_element manpath_element
MANPATH_MAP /bin /usr/share/man
MANPATH_MAP /usr/bin /usr/share/man
MANPATH_MAP /usr/local/bin /usr/local/man
MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
The makewhatis
command actually creates the whatis
database and, by default, makewhatis
reads only /usr/share/man. It’ll skip any manpages in
/usr/local/man and /usr/X11R6/man, because it doesn’t know
they exist!
To gather in those missing manpages, pass these extra
directories to makewhatis
:
# makewhatis /usr/local/man /usr/X11R6/man
#
The superuser can run this command at any time, say, after
installing new software. If you’re a forgetful or appropriately lazy
superuser, consider adding this as a regular cron
job.
Now users will be aware of all of the manpages on the system.
There’s nothing worse than wading through dozens of pages of
information that are irrelevant to your question. Why wade when you
can zero in on the information you want? When you read a manpage,
man
sends the text to your default
pager—a program designed for speedy navigation.
FreeBSD 4.1 replaced the more
pager with less
.
less
is chock-full of useful and
configurable navigation tricks, so this is a case where less really is
more.
Even though your .cshrc
file and man man
show more
as your default pager, remember
more
is now really less
.
less
even comes with its own
help system containing an itemized list of all of its neat tricks.
Whenever you’re in a manpage—or, for that matter, in any file you’ve
sent to a pager—simply type h
to
see the help screen.
I won’t repeat that help here, but Table 9-2 shows some navigational keys to get you moving around.
It’s well worth your time to experiment with how less
formats its output. For example, when
you open a manpage, the prompt at the bottom of your screen indicates
how many bytes of that manpage you’ve read. If you type -m
, you’ll change to the short prompt, a
single colon (:). -M
changes to the
long prompt, which displays the line range you’re currently
viewing.
If you really want to know what line you’re on, try -N
. Read up on -P
to create your own custom prompt
string.
You can also configure how many lines you scroll, also known as the window size. Here I’ll change the window size to 10 lines:
-z
Scroll window size:10
Scroll window size is 10 lines (press RETURN)
Now when I press my spacebar, I’ll scroll down 10 lines instead of the entire screen.
If you experiment with the dozens of options listed in help,
you’ll find that they only last for the contents of the current
manpage. If you find options you like, make them permanent by adding
them to your ~/.cshrc file. Here
I’ll permanently configure the -M
,
or long, prompt and a window size of 10:
setenv LESS Mz10
Note that I’ve simply created a string of desired options, minus
the switch indicator (-
). I’ll also
have to change the line setenv PAGER
more
to setenv
PAGER less
, so that applications that honor
my pager choice will use less
instead of more
. To test your
changes, force the shell to reread its configuration file, then open
up a manpage:
%source ~/.cshrc
%man man
That manpage should now have a customized prompt and window.
Now that you can move around, you’ll want to search for the
information you need. After all, you’re usually looking for something
specific when you read a manpage. Fortunately, less
provides an easy-to-use search feature.
Press /
, the forward slash. Your
prompt will change to /
while
less
waits for you to type in a
search string of one or more words.
Consider adding I
to the
less
configuration in your
.cshrc file to enable
case-insensitive searching. Without it
, searching for /long format
in man ls
will skip the desired section, as
it is entitled The Long
Format
.
Press Enter once you’ve typed in a search string, and less
will take you to the first occurrence
of that string. Repeatedly pressing n
will scroll you through the next
occurrences. Press N
to scroll back
through your search results. If you change your mind and want to
search for something else, press /
.
Suppose you’re reading or searching along and find an interesting bit you’ll want to refer to again. Mark your current position with:
m
mark:a
Here I’ve marked my position with the letter a
. I’ll then carry on with reading the
results of the rest of my search. To return to that position, I simply
type a single quote and the position marker ('a
). You can mark as many as 26 positions
(one for each lowercase letter).
You can also use two single quotes ('') to toggle back and forth
between two positions. For example, I may be in man systat
and can’t believe the display
includes a pigs
option. So I do a
search for /pigs
and read up on
that type of display. '' will bring me back to the original line that
piqued my curiosity. Another '' will put me back at my search
result.
manpath
man man
man makewhatis
man less
Sometimes only the little differences matter.
Despite all your best efforts, eventually you’ll end up with multiple versions of a file. Perhaps you forgot to keep your .vimrc in sync between two machines [Hack #10] . Alternatively, you may want to see the changes between an old configuration file and the new version. You may even want to distribute a bugfix to a manpage or program.
Sending the entire changed file won’t always work: it takes up too
much space and it’s hard to find exactly what changed. It’s often easier
and usually faster to see only the changes (see [Hack
#80] for a practical example). That’s where diff
comes in: it shows the differences
between two files.
As you’d expect, applying changes manually is tedious. Enter
patch
, which applies the changes from
a diff
file.
Suppose you’ve shared a useful script with a friend and both of
you have added new features. Instead of printing out both copies and
marking differences by hand or, worse, trying to reconcile things by
copying and pasting from one program to another, use diff
to see only the differences between the
two programs.
For example, I’ve customized an earlier version of the copydotfiles.pl script from [Hack
#9] to run on Linux instead of FreeBSD. When it
came time to unify the programs, I wanted to see the changes as a
whole. diff
requires two arguments,
the source file and the destination. Here’s the cryptic (at first)
result:
$ diff -u copydotfiles.pl copydotfiles_linux.pl
--- copydotfiles.pl 2004-02-23 16:09:49.000000000 -0800
+++ copydotfiles_linux.pl 2004-02-23 16:09:32.000000000 -0800
@@ -5,8 +5,8 @@
# - change ownership of those files
# You may wish to change these two constants for your system:
-use constant HOMEDIR => '/usr/home';
-use constant SKELDIR => '/usr/share/skel';
+use constant HOMEDIR => '/home';
+use constant SKELDIR => '/etc/skel';
use strict;
@@ -19,8 +19,8 @@
{
for my $dotfile (@ARGV)
{
- my $source = catfile( SKELDIR( ), 'dot' . $dotfile );
- my $dest = catfile( $user->{homedir}, $dotfile );
+ my $source = catfile( SKELDIR( ), $dotfile );
+ my $dest = catfile( $user->{homedir}, $dotfile );
if (-e $dest)
{
This output reveals only three changes. Linux and FreeBSD keep user home directories and skeleton configuration files in different directories. Fortunately, this only involved changing two constants at the top of the file.
The -u
flag produces
unified output, mingling the source and destination lines. It’s not
the default, but it’s the easiest to read and to explain. Count
yourself lucky if you never run across the alternatives.
As you may have guessed from the name, only the differences appear. Each of the two files has a separate marker at the leftmost column. Let’s look at that header again:
--- copydotfiles.pl 2004-02-23 16:09:49.000000000 -0800 +++ copydotfiles_linux.pl 2004-02-23 16:09:32.000000000 -0800
The first line marks the source file, the FreeBSD version. We’re
marking changes against that file. diff
will mark lines that have changed from
that file with a leading minus (-
)
character. The second line marks the destination file, the Linux
version. Lines that have changed in this file appear with a leading
plus (+
) character.
diff
produces output that you
can apply to the first file to produce the second file. That is, you
should remove (or subtract) all of the lines with the leading minus
character and add all of the lines with the leading plus character to
produce the destination file.
The rest of the output consists of hunks. Each hunk also has a header:
@@ -5,8 +5,8 @@
This indicates that the hunk starts on line 5 of the source file and affects eight lines. It also starts on the fifth line of the destination file and affects eight lines—a simple substitution. In general, you can ignore this unless you’re working on something really detailed.
The actual lines of the file are more important. Pay close attention to the leading characters.
# - change ownership of those files # You may wish to change these two constants for your system: -use constant HOMEDIR => '/usr/home'; -use constant SKELDIR => '/usr/share/skel'; +use constant HOMEDIR => '/home'; +use constant SKELDIR => '/etc/skel'; use strict;
Again, this is a simple substitution. Since diff
only works on lines, it has no way of
indicating that only the value of the constants has changed.
By redirecting this output to a file, I can produce a
patch file. Though anyone who can read diff
output could apply those changes
manually, it’s much easier to use the patch
program, especially if the file I’m
patching has had other changes in the meantime. As long as those
changes do not overlap, patch
will
work magically well.
Suppose I’d written:
$ diff -u copydotfiles.pl copydotfiles_linux.pl > dotfiles.patch
Now anyone who wants to apply the changes from the latter file to the former file can apply the patch. Copy the dotfiles.patch file into the same directory as copydotfiles.pl and use the command:
$ patch < dotfiles.patch
patching file copydotfiles.pl
If you’re lucky, the patch will apply with little fanfare. If
you’re unlucky, things may have moved around in your file since the
creation of the patch. In that case, patch
may warn about some fuzz. If I
rearrange a couple of lines in the first hunk that aren’t actually
changed in the patch, I might see a message such as:
$ patch < dot.patch
patching file copydotfiles.pl
Hunk #1 succeeded at 7 with fuzz 2 (offset 2 lines).
If I were really unlucky, I’d have had changes in the lines the
patch also changed. patch
tries as
hard as it can to massage patches, but sometimes it just can’t resolve
things. You’ll see output like this in those cases:
$ patch < dot.patch
patching file copydotfiles.pl
Hunk #1 succeeded at 7 with fuzz 2 (offset 2 lines).
Hunk #2 FAILED at 21.
1 out of 2 hunks FAILED -- saving rejects to file copydotfiles.pl.rej
In this case, it’s up to you, the user, to resolve any changes.
patch
has actually created two new
files, copydotfiles.pl.orig and
copydotfiles.pl.rej. The first
contains the file before any patching attempt; the second contains the
hunks patch
could not apply.
Fortunately, the original file does contain the hunks that could apply without conflicts. In this case, it’s easier to open the copydotfiles.pl.rej file to apply the changes manually.
*************** *** 21,28 **** { for my $dotfile (@ARGV) { - my $source = catfile( SKELDIR( ), 'dot' . $dotfile ); - my $dest = catfile( $user->{homedir}, $dotfile ); if (-e $dest) { --- 21,28 ---- { for my $dotfile (@ARGV) { + my $source = catfile( SKELDIR( ), $dotfile ); + my $dest = catfile( $user->{homedir}, $dotfile ); if (-e $dest) {
This format is a little harder to read than the unified format, but it’s reasonably straightforward. The top half comes from the source file in the patch and represents lines 21 through 28 of the original file. Again, the leading minus character represents lines to remove. The bottom half comes from the destination file in the patch, also lines 21 through 28. This contains two lines to add.
Looking in copydotfiles.pl
around those lines, it turns out that the first line containing
SKELDIR( )
has changed subtly, thus
causing the conflict:
{ for my $dotfile (@ARGV) { my $source = catfile( SKELDIR( ), "dot$dotfile" ); my $dest = catfile( $user->{homedir}, $dotfile ); if (-e $dest) {
I have two options: I could edit the file directly, making the modifications as seen in either the source file or the destination file of the patch, or I could ignore this hunk if the local modifications are better than those of the patch.
In this case, the patch is clearly an improvement. Since it’s only two lines, I’ll just make the changes directly. Otherwise, I could revert the changes in my local file and try to reapply the rejected hunks.
It’s often handy to create patches from normal files, as in the previous example, when sharing code or text with another user. It’s also useful to see the differences between configuration files when upgrading an application. Knowing how to read a diff between your version of httpd.conf and httpd.conf.default can save you hours of debugging time.
What if you want to find differences between entire directories,
though? Suppose you want to see the changes between two versions of a
program. If you can’t upgrade to the new version right away but want
to see if there’s a patch available that you can apply, use diff
on the directories themselves. Be sure
to pass the recursive flag (-r
) if
you want to compare files in subdirectories:
$ diff -ur sdl/trunk SDL_Perl-2.1.0 > sdl_trunk.patch
If that’s not appropriate and you want to patch only a couple of
files at a time, run diff
multiple
times. Append the output to a combined patch. patch
is smart enough to recognize the start
of file markers:
$diff -u sdl/trunk/CHANGELOG SDL_Perl-2.1.0/CHANGELOG >>
sdl_textfiles.patch
$diff -u sdl/trunk/README SDL_Perl-2.1.0/README >>
sdl_textfiles.patch
$diff -u sdl/trunk/INSTALL SDL_Perl-2.1.0/INSTALL >>
sdl_textfiles.patch
Finally, if you need to create a patch for a file that doesn’t
exist, use the null file flag (-n
)
with /dev/null as the
source:
$diff -un /dev/null SDL_Perl-2.1.0/LICENSE >>
sdl_textfiles.patch
This will create the file when someone applies the patch. You
could also touch
the file in the
source directory.
Life’s much easier when you’re working with revision control.
Someday, you may find yourself patching source code or text files in
core BSD. Modify the code in your tree, make sure it works, and then
use cvs
diff -u
to generate patches to mail to the
appropriate development list.
Subversion, the likely successor to CVS, generates the
right kind of patches without the -u
flag—simply use svn diff
. There is a FreeBSD port and a
NetBSD package for Subversion. You can also download binary packages
and source for most operating systems from http://subversion.tigris.org/.
Once you’re used to using patches to keep track of file differences, you may find yourself tempted to keep all important files under version control. Hey, why not?
man diff
man patch
“CVS homedir,” Joey Hess’s Linux Journal article on keeping his home directory in CVS (http://www.linuxjournal.com/article.php?sid=5976)
If you’re new to FreeBSD, you may be wondering where to find information about your system’s hardware and the resources it uses.
You’ve probably noticed that your FreeBSD system didn’t ship with a Microsoft-style Device Manager. However, it does have plenty of useful utilities for gathering hardware information.
When you boot your system, the kernel probes your hardware devices and displays the results to your screen. You can view these messages, even before you log in, by pressing the scroll lock key and using your up arrow to scroll back through the message buffer. When you’re finished, press scroll lock again to return to the login or command prompt.
You can type dmesg
any time
you need to read the system message buffer. However, if it’s been a
while since bootup, it’s quite possible that system messages have
overwritten the boot messages. If so, look in the file /var/run/dmesg.boot, which contains the
messages from the latest boot. This is an ASCII text file, so you can
send it to a pager such as more
or
less
.
You may find it more convenient to search for something
particular. For example, suppose you’ve added sound support to your
kernel by adding device pcm
to your
kernel configuration file. This command will show if the PCM device
was successfully loaded by the new kernel:
% grep pcm /var/run/dmesg.boot
pcm0: <Creative CT5880-C> port 0xa800-0xa83f irq 10 at device 7.0 on pci0
pcm0: <SigmaTel STAC9708/11 AC97 Codec>
In this example, the kernel did indeed probe my Creative sound card at bootup.
Sometimes you just want to know which devices are using which system resources. This command will display the IRQs, DMAs, I/O ports, and I/O memory addresses in use:
% devinfo -u
Interrupt request lines:
0 (root0)
1 (atkbd0)
2 (root0)
3 (sio1)
4 (sio0)
5 (rl0)
6 (fdc0)
7 (ppc0)
8 (root0)
9 (acpi0)
10 (pcm0)
11 (rl1)
12 (psm0)
13 (root0)
14 (ata0)
15 (ata1)
DMA request lines:
0-1 (root0)
2 (fdc0)
3 (ppc0)
4-7 (root0)
I/O ports:
0x0-0xf (root0)
0x10-0x1f (acpi_sysresource0)
0x20-0x21 (root0)
<snip>
I/O memory addresses:
0x0-0x9ffff (root0)
0xa0000-0xbffff (vga0)
0xc0000-0xcbfff (orm0)
0xcc000-0xfbffffff (root0)
0xfc000000-0xfdffffff (agp0)
0xfe000000-0xffffffff (root0)
Alternately, use devinfo -r
if you prefer to see your listing by device.
If you’re unsure what a device is, use the whatis
command. For example, in my listing,
ppc0
uses IRQ 7 and DMA 3. To find
out what ppc0
is:
% whatis ppc
ppc(4) Parallel Port Chipset driver
Don’t include the trailing number when using the whatis
command.
There are several ways to gather network interface information. One of the handiest is
the -i
switch to netstat
:
% netstat -i
Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll
rl0* 1500 <Link#1> 00:05:5d:d2:19:b7 0 0 0 0 0
rl1* 1500 <Link#2> 00:05:5d:d1:ff:9d 0 0 0 0 0
ed0 1500 <Link#3> 00:50:ba:de:36:33 15247 0 11301 0 78
ed0 1500 192.168.2 genisis. 15091 - 11222 - -
lp0* 1500 <Link#4> 0 0 0 0 0
lo0 16384 <Link#5> 179 0 179 0 0
lo0 16384 your-net localhost 179 - 179 - -
This command shows all interfaces, both physical and virtual.
This particular system has three network interface cards: rl0
, rl1
,
and ed0
. The first two interfaces
are shut down, as indicated by the *
after the device name. These three are
Ethernet cards, as indicated by their MAC addresses. (This is also an
excellent way to find all of the MAC addresses on your system).
The ed0
interface and
loopback interface (lo0
) have each
been configured with a hostname and an IP address, as indicated by the
Network
column. If you’re only
interested in seeing interfaces configured with an IPv4 address, add
the -f
(family) switch:
% netstat -i -f inet
ed0 1500 192.168.2 genisis. 15091 - 11222 - -
lo0 16384 your-net localhost 179 - 179 - -
You can also find hardware information by using kenv
to view your kernel environment.
kenv
will dump several screens
worth of information, so use grep
when possible to zero in on the information you want. For example, to
view IRQ information:
% kenv | grep irq
hint.ata.0.irq="14"
hint.ata.1.irq="15"
hint.atkbd.0.irq="1"
hint.ed.0.irq="10"
hint.fdc.0.irq="6"
hint.ie.0.irq="10"
hint.le.0.irq="5"
hint.lnc.0.irq="10"
hint.pcic.1.irq="11"
hint.ppc.0.irq="7"
hint.psm.0.irq="12"
hint.sio.0.irq="4"
hint.sio.1.irq="3"
hint.sio.2.irq="5"
hint.sio.3.irq="9"
hint.sn.0.irq="10"
If you’re unsure what is using a listed IRQ, use whatis
to look up the second word (the one
after hint
). For example, this will
show what is using my IRQ 12:
% whatis psm
psm(4) - PS/2 mouse style pointing device driver
I actually prefer the output of kenv
to that of devinfo
. Here, I’ll search for the I/O
addresses used by my COM ports:
% kenv | grep port | grep sio
hint.sio.0.port="0x3F8"
hint.sio.1.port="0x2F8"
hint.sio.2.port="0x3E8"
hint.sio.3.port="0x2E8"
To see which devices are disabled:
% kenv | grep disabled
hint.sio.2.disabled="1"
hint.sio.3.disabled="1"
BSD gives the first com port the number zero, so it looks like I have COM3 and COM4 disabled on this system.
As a system administrator, it pays to know what’s happening on your systems.
Sure, you spend time reading your logs, but do you take advantage of the other information-gathering utilities available to you? Silently, in the background, your system tracks all kinds of neat information. If you know enough to peek under the system hood, you can get a very good view of what is occurring on the system at any given point in time.
For the experienced hacker, the output from these commands may suggest interesting scripting possibilities.
Have you ever needed to know who logged into a system and for
how long? Use the users
command to see who’s logged in now:
% users
dru biko
Perhaps you prefer to know who is on which terminal. Try who
. Here, the H
includes column headers and the u
shows each user’s idle time:
% who -Hu
NAME LINE TIME IDLE FROM
dru ttyv1 Jan 25 08:59 01:00
biko ttyv5 Jan 25 09:57 .
dru ttyp0 Jan 25 09:58 00:02 (hostname)
Feel free to experiment with who
’s switches to find an output that suits
your needs. Here, dru
and biko
have logged in physically at this
system’s keyboard using v
irtual
terminals 1 and 5. dru
has also
logged in over the first p
seudoterminal (over the
network) from the specified hostname.
To find out what everyone is doing, use w
:
% w
10:07AM up 1:20, 9 users, load averages: 0.02, 0.02, 0.09
USER TTY FROM LOGIN@ IDLE WHAT
dru v1 - 8:59AM 1:08 pine
biko v5 - 9:57AM - w
dru p0 hostname 9:58AM 4 -csh (csh)
Notice that as a regular user, I was easily able to find out who is logged in, where they are, and what they’re currently doing. If you don’t want regular users knowing what commands other users are currently running, see [Hack #57] .
You’re not limited to finding out what’s happening at this
particular moment. Use lastlogin
to
see the most recent time at which each of your users logged in:
% lastlogin
dru ttyv1 Sun Jan 25 08:59:36 2004
biko ttyv5 Sun Jan 25 09:57:18 2004
dlavigne ttyv6 Sat Jan 24 09:48:32 2004
dru ttyp0 hostname Sun Jan 25 09:58:50 2004
rembackup ttyp0 hostname Fri Jan 23 01:00:00 2004
For a slightly different output, last
can show who is still logged in:
% last | grep still
dru ttyp0 hostname Sun Jan 25 09:58 still logged in
dru ttyv1 Sun Jan 25 08:59 still logged in
biko ttyv5 Sun Jan 25 09:57 still logged in
Do you need a record of system shutdowns or reboots? The /var/log/wtmp database holds this
information. Use last
to view the
desired statistics:
%last reboot
reboot ~ Tue Jan 20 15:37 reboot ~ Tue Nov 25 07:24 reboot ~ Sun Aug 3 09:05 wtmp begins Tue Jul 1 15:27:26 EDT 2003 %last shutdown
shutdown ~ Wed Dec 24 22:14 wtmp begins Tue Jul 1 15:27:26 EDT 2003
Another option to consider is enabling system accounting, which maintains a database of extremely detailed statistics of every process and subprocess that has been executed on a system.
#touch /var/account/acct
#accton /var/account/acct
Note that the accton
command
will fail if you don’t specify the name of the accounting log or if
that log doesn’t already exist. Also, in a queer case of logic, typing
accton
with no
arguments really turns accounting off.
Once accounting is enabled, use lastcomm
to view
the contents of /var/account/acct:
% lastcomm
lastcomm - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
man - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
sh - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
sh -F dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
less - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
col - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
groff - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
grotty - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
troff - dlavigne ttyv6 0.08 secs Sun Jan 25 11:33
tbl - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
zcat - dlavigne ttyv6 0.00 secs Sun Jan 25 11:33
cron -F root __ 0.00 secs Sun Jan 25 11:33
sh - operator __ 0.00 secs Sun Jan 25 11:33
sh - operator __ 0.00 secs Sun Jan 25 11:33
dd - operator __ 0.00 secs Sun Jan 25 11:33
mv - operator __ 0.00 secs Sun Jan 25 11:33
mv - operator __ 0.00 secs Sun Jan 25 11:33
mv - operator __ 0.00 secs Sun Jan 25 11:33
rm - operator __ 0.00 secs Sun Jan 25 11:33
jot - operator __ 0.00 secs Sun Jan 25 11:33
accton - root ttyv0 0.00 secs Sun Jan 25 11:32
This comes from a quiet system one minute after enabling
accounting. A cron
job happened to
be running at the time, hence the operator
lines. The user dlavigne
also opened up a manpage during
that period. Note all of the processes involved before man
actually started.
This command can also show you which processes ended
abnormally. Search for the D
flag, which indicates that the process dumped core:
% lastcomm | grep -w "D"
Depending upon your security requirements, you may not want
users to have access to such detailed information. After all, lastcomm
will show every process run by
every user. Tightening permissions will fix that:
#chmod 600 /var/account/acct
#su dlavigne
%lastcomm
lastcomm: /var/account/acct: Permission denied
Also, if you’re planning on using lastcomm
as an extra audit trail, consider
changing this file’s flags
[Hack #56] . You’ll also want
to have plenty of disk space on the filesystem holding the
database.
Finally, to enable system accounting when the system boots, add this line to /etc/rc.conf:
accounting_enable="YES"
man users
man who
man w
man lastlogin
man last
man lastcomm
For those who edit their text at the command line.
Like most computer users, you probably find yourself spending a fair bit of time typing, whether responding to email, navigating the web, or working on that résumé or thesis. How often do you find yourself looking at a word, wondering if you’ve spelled it correctly? How often do you rack your brain trying to find a more interesting or descriptive word?
You’ve probably discovered that Unix doesn’t come with a built-in dictionary or thesaurus. Sure, you can install a feature-rich GUI office suite, but what alternatives are there for users who prefer less bloat on their systems or are accessing systems from the command line?
If you’re in doubt about the spelling of a word, try using look
. Simply
include as much of the word as you’re sure about. For example, if you
can’t remember how to spell “bodacious” but you’re pretty sure it
starts with “boda”:
% look boda
bodach
bodacious
bodaciously
If you don’t have access to a GUI, see [Hack #12] .
I find look
especially
helpful with suffixes. It’s very handy if you can’t remember when to
use “ly”, “ally”, or “ily”. For example:
% look mandator
mandator
mandatorily
mandatory
look
is a useful spellchecker, but it won’t show you the
meanings or synonyms of a word. Accordingly, I found myself spending a
fair bit of time at http://dictionary.reference.com/. While there, I
noticed a pattern. Whatever word I searched for was appended to the
URL as search?q=<myword>. Whenever I used
the dictionary, the URL started with dictionary,
which changed to the word thesaurus whenever I
did a thesaurus lookup. That suggested to me that it would be very
easy to generate my own custom lookup utility, so I started out with
these two scripts:
%more ~/bin/dict
#!/bin/sh # script to look up the definition of word from dictionary.reference.com # replaces $1 with user's search string # or gives error message if user forgets to include search string if test $1 then w3m "http://dictionary.reference.com/search?q="$1"" else echo "Don't forget to include the word you would like to search for" exit 1 fi %more ~/bin/thes
#!/bin/sh # script to find the synonym of word from thesaurus.reference.com # replaces $1 with user's search string # or gives error message if user forgets to include search string if test $1 then w3m "http://thesaurus.reference.com/search?q="$1"" else echo "Don't forget to include the word you would like to search for" exit 1 fi
Recognize those positional parameters we saw before in [Hack #13] ? When I use either script, I include the word that I would like to look up.
The utility I chose to grab the results is the command-line browser w3m
, which can be built from /usr/ports/www/w3m. If you have already
installed another command-line browser, such as lynx
or links
, specify your browser in your own
script. Don’t forget to make your script executable with chmod
+x
.
Then, to look up the meaning of a word:
% dict palladium
Or, to find its synonyms and antonyms:
% thes brusque
If you’re not stuck at the command line, Mozilla-based browsers allow you to create similar shortcuts. See Asa Dotzler’s article on custom keywords at http://www.mozilla.org/docs/end-user/keywords.html.
Well, that’s a fair start—my browser now automagically takes
me to the correct section of an online dictionary or thesaurus
whenever I’m curious about a particular word. However, what if I want
to forgo using a browser altogether? FreeBSD comes with the fetch
utility specifically to retrieve web information. Why not use it to retrieve the
results?
Before editing my scripts, I tried various invocations of
fetch
at the command line until I
had achieved my desired results. I started out by replacing w3m
with fetch
(note that I had to supply a word, in
this case test
, as I was at the
command line, not within a script):
% fetch "http://dictionary.reference.com/search?q=test"
This worked, but it resulted in a file called search?q=<myword>, where <myword> was the word I had supplied as the parameter. After a while, my home directory would be full of hundreds of files starting with search?q.
So, I specified the name of a file to which to write the results:
% fetch -o results "http://dictionary.reference.com/search?q=test"
Now, regardless of the number of times I use my script, I’ll only have one file called results. There’s a problem with that file, though. It’s an HTML file, so unless I enjoy wading through HTML tags in order to read my results, I have to open up that file in a browser. That sorta defeats my goal of not using a browser.
So, I went out on the Web looking for an HTML-to-ASCII
converter. I tried out several before settling on a Perl script called
html2txt
.
I then tried piping the results file to the converter:
%fetch -o results "http://dictionary.reference.com/search?q=test"
| html2txt results
Cannot open HTML source file : results, Error No such file or directory Receiving results: 21791 bytes
That’s when I hit a timing issue. It takes a few seconds for
fetch
to retrieve the file, so
html2txt
complains when the shell
asks for it to work on that (as of yet) nonexistent file. To solve
that, I asked the shell to wait until after fetch
was finished by using &&
instead of |
:
%fetch -o results "http://dictionary.reference.com/search?q=test"
&& html2txt results
To finish off my command, I ask for the ASCII-fied file to be opened up in a pager so I can view the results:
%fetch -o results "http://dictionary.reference.com/search?q=test"
&& html2txt results && more results.txt
Note that this particular converter creates an ASCII file with the same name, but with a .txt extension.
Did you know that your system has a built-in crossword-puzzle solver? You may never have to leave a square empty again if you remember this little trick.
Consider a word that resembles:
t _ _ _ k _ _ _r
This one-liner will show your possibilities, allowing you to choose the word that matches the clue definition:
% grep -wi 't...k...r' /usr/share/dict/words
thickener
trickster
trinketer
truckster
Here, grep
searched through
the dictionary words installed on your system. (This is the same file
that look
searches.) Use single
quotes for your search phrase, and replace each blank square in your
crossword with a ..
man fetch
The Perl HTML-to-text converter at http://www.ftls.org/en/examples/perl-tools/html2txt.shtml
“Wanna Cheat at Crosswords?” (http://www.osxfaq.com/tips/unix-tricks/week23/friday.ws)
Use your terminal’s built-in timers and schedulers.
You know how it is. You sit down in front of a keyboard and quickly become absorbed in your work. At some point you remember to look up, only to notice that everyone else is gone for the day. If that doesn’t describe you, I bet you can think of at least one person it does describe.
Fortunately the leave
command can save you from the embarrassment of
forgetting important appointments. Use it at any time by
typing:
% leave
When do you have to leave?
There are three ways to respond to that question:
Press Enter to abort.
Type hhmm
, where
hh
represents the hour and
mm
represents the minute.
Type +
number
, where
number
represents how many hours or
minutes from now you’d like to leave.
For example, to leave at 5 PM:
% leave 500
Alarm set for Tue Dec 30 17:00:00 EST 2003. (pid 50097)
leave 1700
will achieve the
same results.
Or, to leave in 45 minutes:
% leave +45
Alarm set for Tue Dec 30 9:52:00 EST 2003. (pid 50108)
Be sure to include the +
if
you’re not specifying an actual time.
You can then carry on with your day. Five minutes before it’s time to leave, your terminal will beep and display this message:
You have to leave in 5 minutes.
You’ll receive another warning one minute before the set time,
then every minute thereafter. leave
definitely works for the procrastinator and those who always need to
do just one more thing before leaving. The only way to end the
incessant nagging is to log out or killall
leave
(but please don’t take that last command
literally!).
Consider placing /usr/bin/leave in /usr/share/skel/dot.cshrc [Hack #9] .
leave
is nice for scheduling
your own departure, but what if you want to schedule the execution of
commands? I bet you’re thinking “use at
or cron
.” Have you ever tried the scheduler built into tcsh
?
While sched
can execute any
command at a given time, you can also use it as a reminder system. I
use it as a terminal sticky-note system that won’t clutter up my
monitor. For example, it’s 9:00, I’ve just logged in, and I’m mulling
over my to-do list for the day. As I mentally review my list, I type
the following:
%sched 11:55 echo Lunch with Robyn today.
%sched 2:30 echo Reminder: project due by 4:30.
%sched 5:00 echo Go home!!!
Now at any point in the day I can review my to-do list:
% sched
1 11:55 echo Lunch with Robyn today.
2 2:30 echo Reminder: project due by 4:30.
3 5:00 echo Go home!!!
As each appointed time arrives, the desired reminder will appear on my terminal.
To remove an item from your to-do list, simply type sched -
#
, where
#
represents the number of that item in the
schedule. Logging out of your shell will also remove all items from
your list since sched
is a shell
command.
What if you plan on logging out during the day? You certainly don’t want to recreate your schedule every time you log in. It’s a simple matter to save the schedule. Place this line in your ~/.logout file:
sched > schedule
This will send the output of sched
to a file in your home directory
called schedule, saving any items
in your to-do list to the specified file when you log out.
Unfortunately, there’s no simple way to pipe that list back into
sched
when you log back in. This
has to do with how the C shell handles its built-in commands. You
would think that:
% sched < schedule
would reverse the process, but it doesn’t. If you really miss your shell sending you reminders at their appointed times, consider locking your terminal [Hack #7] instead of logging out during the day.
man leave
man tcsh
Until recently, running Java applications on FreeBSD meant using the Linux compatibility mode.
Linux programs can sometimes be problematic on FreeBSD. Java© uses threading very heavily, and that’s probably the poorest-emulated part of Linux binary compatibility. Some Java applications or class libraries just don’t work correctly under Linux emulation. Native versions of the Java distribution had restrictive licenses, and it required a great deal of work to download and compile them. Fortunately, the FreeBSD Foundation has negotiated a FreeBSD Java license with Sun Microsystems. This hack demonstrates how to configure the FreeBSD version of Java.
What about native Java on NetBSD or OpenBSD? At the time of writing, neither system had a native Java port. You can run Java on a Linux emulator or via Tomcat.
The first requirement for running Java applications is a Java Virtual Machine (JVM) and the associated runtime support libraries. There are several Java Runtime Environments (JREs) or Java Development Kits (JDKs) available in ports.
A JRE contains everything necessary for an end user to run Java applications. A JDK contains all that, plus various extra bits required for developing, compiling, and debugging Java code.
The main criteria for choosing a port are:
Which version of Java do you need?
Do you want to run FreeBSD native code or Linux code run under emulation?
Do you prefer to run a precompiled binary or compile it yourself from source code?
Unless you have a specific requirement for an earlier version, choose the latest stable release, which, as of this writing, is Java 1.4.2. The native version, found in /usr/ports/java/jdk14, will give you the best performance, but you will have to compile it yourself. That is more easily said than done: compiling the JDK requires a great deal of disk space and CPU power, as well as a working copy of the 1.4.2 JDK. The first time you compile, you will have to install one of the Linux JDKs, such as the recommended /usr/ports/java/linux-sun-jdk14, but once you have a working native JDK, you can use it to compile any updates and uninstall the Linux version.
You can install several Java versions simultaneously without them interfering with each other. Each will install into its own subdirectory of /usr/local.
If you need a precompiled native version, choose one of the Diablo Java 1.3.1 ports. These use the same code base as the /usr/ports/java/jdk13 port, and they’re certified, licensed, and released through the sponsorship provided by the FreeBSD Foundation (http://www.freebsdfoundation.org/downloads/java.shtml).
Diablo JDK 1.4 and JRE 1.4 versions are under development, but not yet available.
The Diablo Java packages are standard FreeBSD packages, so you
can install them via pkd_add
.
However, you’re better off installing from the Diablo ports, as that
will provide you with the correct dependencies.
For example, to install the Latte Diablo JRE 1.3.1 port, visit http://www.freebsdfoundation.org/cgi-bin/download.cgi?package=diablo-jre-1.3.1.0.tgz. Read and accept the license terms, and save the downloaded file as /usr/ports/distfiles/diablo-jre-1.3.1-0.tar.bz2. Then:
#cd /usr/ports/java/diablo-jre13
#make install
Starting up any Java application means running a Java Virtual
Machine, which in turn loads a named Java class. That class is the
entry point for the program. The JVM always requires the CLASSPATH
environment variable to contain a list of .jar archives that store all of the Java
classes required by the application. You can provide extra arguments
to the JVM—to limit its use of memory or other system resources, for
example—and the application itself may take further command-line
arguments.
Many Java applications provide a shell script to set up the
environment and to execute the JVM with the appropriate arguments. A
typical example is ant
(see
/usr/ports/devel/apache-ant), the
Java equivalent to make
.
The installation process edits the script that will become
/usr/local/bin/ant to use the
Java version used when building the port. However, you can override
the default Java version within the script by setting the JAVA_HOME
environment variable:
% setenv JAVA_HOME=/usr/local/jdk14
Given the wide variety of JVMs available under FreeBSD, adding
code to all Java application wrapper scripts or otherwise configuring
standalone Java applications to use the correct JVM could become a
maintenance nightmare. Fortunately, the /usr/ports/java/javawmwrapper port provides
the /usr/local/bin/javavm script,
which all applications can run to discover the site’s default JVM.
javavm
’s configuration file,
/usr/local/etc/javavms, contains
a list of installed JVMs in the order of their preference. Installing
or removing a JVM through ports will modify this file. You can also
edit it by hand.
In the case of a Java applet, the web browser starts the JVM and downloads and runs the applet from the Web. Applets run in a special sandbox that denies them access to most of the local system, except for the browser window.
Java support in web browsers derived from Netscape (including Mozilla, Firebird, and Galeon) uses a plug-in that comes standard with the JDK. For the native JDK 1.4.2, the plug-in is /usr/local/jdk1.4.2/jre/plugin/i386/ns610/libjavaplugin_oji.so. To make this plug-in available to web browsers, create a symlink to this file from /usr/X11R6/lib/browser_plugins:
#cd /usr/X11R6/lib/browser_plugins
#ln -s /usr/local/jdk1.4.2/jre/plugin/i386/ns610/libjavaplugin_oji.so .
Launch a web browser and type about:plugins
into the location bar. You
should see an entry for the “Java(TM) Plug-in,” which claims to handle
about 30 MIME types, all variants on application/x-java-
something.
A servlet is all or part of a web application written in Java. It runs through a servlet container application, which abstracts out all of the common server-side functionality. Tomcat (/usr/ports/www/jakarta-tomcat41) and Jetty (/usr/ports/www/jetty) are two examples of these applications.
The servlet container application runs in much the same way as standalone Java applications.
WebStart is a web-based mechanism for downloading and
updating Java applications. Use the Preferences menu item in javaws
to control the JVM that will run the
WebStart-ed applications. Unlike applets, the downloaded applications
run independently of the web browser. You don’t need to download them
again each time they run. They also have full access to the underlying
system. The javaws
application is a
standard part of Java 1.4 or above. It lives in ${JAVA_HOME}/jre/javaws/javaws.
FreeBSD Foundation’s Java downloads (http://www.freebsdfoundation.org/downloads/java.shtml)
End your email communications with a short witticism.
We all seem to know at least one geek friend or mailing-list poster whose emails always end with a different and humourous bit of random nonsense. You may be aware that this is the work of her ~/.signature file, but have you ever wondered how she manages to rotate those signatures?
While there are several utilities in the ports collection that
will randomize your signature, it is easy enough to roll your own
signature rotator using the fortune
program and a few lines of shell scripting.
Your approach will vary slightly, depending on whether your
particular mail user agent (MUA) supports pipes. If it does, it’s
capable of interpreting the contents of a file as command output, just
like when you use a pipe (|
) on the
command line.
I use pine
, which supports both static signature files and
signatures that come from the piped output of a signature rotation
program.
When configuring pine
, choose
Setup
from the main menu, then
C
for the configuration editor.
Find the signature-file
option and
give it this value:
.signature |
The pipe character tells pine
to process that filename as a program instead of inserting its
contents literally.
Also enable the signature-at-bottom
option found in the Reply
Preferences
to ensure your signature is placed at the bottom
of your emails, even when replying to an email.
Next, create a file called ~/.signature containing these lines:
echo "Your random fortune:" /usr/games/fortune -s
This isn’t quite a shell script: I don’t have to include the
#!/bin/sh
line or use chmod +x
to set the file as executable.
However, pine
will execute those
two lines whenever I compose or reply to an email, adding something
like this to the bottom of the email:
Your random fortune: "Right now I'm having amnesia and deja vu at the same time." -- Steven Wright
I also included the short switch (-s
) to fortune
, as it’s bad Netiquette to end an
email with a long signature.
If you try a few test messages, you’ll see that every email receives a different, random signature.
Depending upon your audience, you may wish to filter further the
fortunes to use as signatures. You’ll find the available fortunes in
/usr/share/games/fortune. If your
friends are Trekkies, modify the fortune
line in your ~/.signature like so:
/usr/games/fortune -s startrek
If they tend to be cynical, try murphy
instead.
Some MUAs, such as Mozilla’s mailer, don’t support pipes. You’ll know yours doesn’t if your test message produces no fortune. Fortunately, there’s another option.
Create a file as before, but this time make it a Bourne script.
I’ll save mine in ~/bin and make
it executable using chmod
+x
:
#!/bin/sh echo "Your random fortune:" > $HOME/.signature /usr/games/fortune -s >> $HOME/.signature
This script does two things. It echo
es the first line to the ~/.signature file, then appends the results
of the fortune
program to the same
file.
To configure Mozilla to use this signature file, open the Mail & Newsgroups window, and choose Mail & Newsgroups Account Settings from the Edit menu. Select the “Attach this signature” option from the main menu, and use the Choose button to give the location of ~/.signature.
What do you think will happen when I compose an email? Since Mozilla only understands literal signature files, it will faithfully reproduce the current contents of ~/.signature. If I haven’t run my script yet, that file doesn’t exist. If I have run the script, the resulting file remains the same until the script runs again.
This is different from pine
,
which has the capability of executing the commands found in my
signature file. Since Mozilla can’t, you’ll have to remember to run
the script manually before you compose an email or schedule its
periodic execution using cron
. This
may be a little disappointing if you want every recipient to receive a
unique signature, or not a big deal if you send only one or two emails
a day and aren’t a stickler for randomness.
Hmm, what would happen if .signature were a named pipe connected to a program that provided a random signature on every read? There are many possibilities here.
man fortune
Unix is amazing. Only your imagination limits the usefulness of the built-in commands. You can create your own commands and then pipe them together, allowing one utility to work on the results of another.
If you’re like me, you’ve run across dozens of useful combinations over the years. Here are some of my favorite one-liners, intended to demonstrate useful ideas as well as to prime your pump for writing your own one-liner hacks.
Have you ever downloaded an extremely large archive over a slow connection? It seems to take forever to receive the archive and forever to untar it. Being impatient, I hate not knowing how many of the archived files are already here. I miss the ability to work on those files while the rest of the archive finishes its slow migration onto my system.
This one-liner will decompress and untar the files as the archive downloads, without interfering with the download. Here’s an example of downloading and untarring the ports collection:
# tail -f -b 2048 ports.tar.gz | tar -zvxf -
ports/
ports/Mk/
<snip>
Here I’ve asked tail
to
stream up to one megabyte of the specified file as it is received. It
will pipe those bytes to the tar
utility, which I’ve directed to decompress (-z
) and to extract (x
) the specified file (f
) while displaying the results verbosely
(v
).
To use this command, download the archive to where you’d like to untar it—in this example, /usr. Simply replace the filename ports.tar.gz with the name of your archive.
Do you ever need to know the last modification date of a file? Consider a long listing:
% ls -l filename
-rw-r--r-- 1 dru wheel 12962 Dec 16 18:01 filename
If you count the fields, the sixth (Dec
), seventh (16
), and eighth (18:01
) fields all contain part of the
modification date. However, there’s whitespace separating those
fields, which makes it difficult to determine their exact character
positions. Fortunately, awk
doesn’t
mind variable whitespace, so this one-liner will always work:
%echo filename was last modified on `/bin/ls -l filename
| awk '{print $6, $7, $8}'`
filename was last modified on Dec 16 18:01
Here I’ve asked echo
to
repeat a string as well as the results of a command contained within
single quotes. The first half of that command is simply ls -l
filename
. I’ve piped the output of that
command to awk
, which will print
the sixth ($6
), seventh ($7
), and eighth ($8
) fields of the long listing. Note that
the awk
action is enclosed between
'{ }
‘.
While this is a useful one-liner, it is fairly awk
ward to type as needed. However, if you
replace filename
with a positional
parameter [Hack #13] , you have a very handy
script. I’ll call mine when
:
% more ~/bin/when
#!/bin/sh
# script to list date of a file's last modification
# replaces $1 with specified filename
# or gives error message if user forgets to include filename
if test $1
then
echo $1 was last modified on `/bin/ls -l $1| awk '{print $6, $7, $8}'`
else
echo "Don't forget the name of the file you're interested in"
exit 1
fi
Once you’ve made your script executable, use when filename
to find the date of a file’s
most recent modification.
If you ever need to find symbolic links, you’re in luck.
find
’s -type l
or link option serves just this
purpose. Start with this invocation:
% find /etc -type l -ls
25298 0 lrwxrwxrwx 1 root wheel 23 Apr 7
2003 /etc/termcap -> /usr/share/misc/termcap
25299 0 lrwxrwxrwx 1 root wheel 13
Apr 7 2003 /etc/rmt -> /usr/sbin/rmt
25301 0 lrwxrwxrwx 1 root wheel 12
Apr 7 2003 /etc/aliases -> mail/aliases
25305 0 lrwxr-xr-x 1 root wheel 36
Oct 26 09:08 /etc/localtime -> /usr/share/zoneinfo/America/Montreal
Well, that worked, but the output is downright ugly. Let’s pipe
the results to our good friend awk
to display only
the last three fields. If you count them, those are fields 11 through
13:
% find /etc -type l -ls | awk '{print $11, $12, $13}'
/etc/termcap -> /usr/share/misc/termcap
/etc/rmt -> /usr/sbin/rmt
/etc/aliases -> mail/aliases
/etc/localtime -> /usr/share/zoneinfo/America/Montreal
Aah, much better. If you ever plan on needing to find symlinks,
it’s well worth saving this in a shell script similar to the when
script shown previously.
Are you always forgetting the meanings of the various fields
in a crontab
? It would probably be
a lot easier if your crontab
began
like this:
# minute (0-59), # | hour (0-23), # | | day of the month (1-31), # | | | month of the year (1-12), # | | | | day of the week (0-6 with 0=Sunday). # | | | | | commands 3 2 * * 0,6 /some/command/to/run
To achieve that, type those lines into a text file, say
~/cronheader. (Be patient, we’re
getting to the one-liner.) Then, open up your crontab
editor:
% crontab -e
Unless you’ve changed your default editor, this will open up
your crontab
using vi
. Place your cursor at the beginning of
the file, and type the following:
!!more /usr/home/dru/cronheader
The !!
tells vi
to insert the output of the specified
command. Be sure to give the full pathname to your file. vi
will insert its contents for you once you
press Enter. When you’re finished, type :wq
as usual to exit the editor.
man tail
man tar
man cut
man awk
Use the utilities that come with the core X distribution.
There are so many GUI utilities, available either as part of your favorite Window Manager or as a separate installation, that you can forget that the core X distribution also provides several useful and lightweight programs. Do you need to monitor console messages, manage your clipboard, send pop-up messages, or create and view screenshots? Before you hit the ports collection, give the built-in utilities a try.
In [Hack #42] , we saw how to redirect console messages. If you’re using an
X session, the xconsole
utility fulfills this purpose. To start this utility,
simply type its name into an xterm
or use the Run command provided by your window manager.
By default, only the superuser can start xconsole
. A regular user will instead
receive a Couldn't open console
message. This is a safety precaution on multiuser systems, preventing
regular users from viewing system messages. If you’re the only user
who uses your system, remove the comment (#
) from this line in /etc/fbtab:
#/dev/ttyv0 0600 /dev/console
If you spend a lot of your time at an X session, consider adding
xconsole
to your ~/.xinitrc file so it will start
automatically (see [Hack #9] ).
If you do a lot of copying and pasting, xclipboard
is another excellent candidate for automatic startup.
This utility stores each of your clipboard selections as a separate
entity, allowing you to scroll through them one at a time in a simple
GUI window. In addition to the Next and Prev buttons, a Delete button
lets you remove unwanted items and a Save button allows you to save
all of your items as a file.
Do you find yourself starting a command that takes a while
to execute, continuing your work in an X session, then returning
periodically to the original terminal or xterm
to see how that command is perking
along? Wouldn’t it be easier to send yourself a pop-up message once
the command completes?
For example, suppose I want to know when the script from [Hack #80] finishes. I could execute that script as follows:
#~/bin/mycustomupgrade.sh && xmessage -nearmouse cvsup is complete.
When the upgrade completes, a pop-up message with the text
cvsup is
complete
. will appear in my X session near
my mouse. That message will disappear once I click on the Okay
button.
If you’re in the habit of using su
-l
to provide a new login when you become the superuser,
you’ll find that the preceding command will fail to send you a pop-up
menu. (I’m assuming you’re logged in as a regular user when you start
your X session. You should be!) Instead, you’ll receive this error
message:
Xlib: connection to ":0.0" refused by server Xlib: No protocol specified Error: Can't open display: :0.0
This has to do with the X authorization process. If I start my X
session as the user dru
and use
su
to execute a command, I’m still
logged in as dru
, so I’m allowed to
send a message to my display. However, if I use su -l
to execute the command, I’m no longer
logged in as dru
but as root
. The X server refuses to let another
user interfere with my display, which is a good thing.
A quick workaround is to not use su
-l
when sending pop-up messages to your regular user
account. An alternative is to understand the X authorization process.
You can then use this knowledge to enable the superuser to send a
message to any user on any display.
Your X server uses a token known as an MIT magic cookie to provide authorization. When you start your X session, the server creates and stores this unique cookie in ~/.Xauthority. You can view it at any time using this command:
% xauth list
genisis/unix:0 MIT-MAGIC-COOKIE-1 7e7bc20f9413469a7376e2e5c91aa6f1
Take note that you’re the only user with access to this file:
% ls -l ~/.Xauthority
-rw------- 1 dru wheel 101 Feb 18 13:28 .Xauthority
Always keep in the back of your mind, though, that file
ownership does not matter to the superuser. For example, if I need
to send an important message to the user dru
, I can ssh
into the system she’s working on and
become the superuser. Then:
# cp ~dru/.Xauthority .
I now have a copy of dru
’s
magic cookie. However, before I can use it, I’ll first have to
change my display. Since I ssh
ed
into a terminal, I currently don’t have one:
# echo $DISPLAY
DISPLAY: Undefined variable.
I don’t want just any display, I want the display dru
is currently using. I can find the
name of her display by reading her magic cookie:
# xauth list
genisis/unix:0 MIT-MAGIC-COOKIE-1 7e7bc20f9413469a7376e2e5c91aa6f1
The name of her display is genisis/unix:0
, where genisis
represents the hostname of the
system. I’ll now attach to that display and send my message:
#setenv DISPLAY genisis/unix:0
#xmessage -nearmouse Time to go home, Dru...
(prompt hangs until dru responds by pressing the "Okay" button)
This cheat works on any system to which you have superuser access. Technically, you can execute any command X understands in a user’s X session once you have his cookie and display. Do remember to use your superuser powers for good, though.
Have you ever needed to send a user a screenshot? There are ports available for this purpose,
but the built-in X command xwd
will
suffice. Creating a screenshot is a simple matter of:
% xwd -out screenshot.xwd
The command will appear to hang as it waits for you to click
your mouse on the portion of the screen you’d like to capture. Use the
-root
switch to capture the entire
screen and save yourself a click.
You can view and manipulate the resulting file with most
third-party image editors, including xv
and gimp
. For quick viewing, though, nothing
beats the built-in xwud
:
% xwud -in screenshot.xwd
Your results won’t seem that impressive if you use xwud
immediately, as your screen still
probably looks like your screenshot. When you’re finished viewing the
screenshot, press Ctrl-c.