Chapter 9. Grokking BSD

Introduction

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.

How’d He Know That?

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.”

Online Resources

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.

Keeping Offline Resources Up-to-Date

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.

Tip

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=.

Tip

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.

What Did the Manpage Forget to Say?

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.

See Also

  • man hier (includes a description of the contents of /usr/share/doc/)

  • man tail

Create Your Own Manpages

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?

Manpage Basics

Creating a manpage isn’t all that difficult. After all, a manpage is simply a text file—more specifically, a gzipped 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.

Creating a Manpage

You can whip up a nicely formatted manpage by knowing only three groff commands, as shown in Table 9-1.

Table 9-1. groff commands

Command

Usage

."

A comment

.TH

The title

.SH NAME

The only required section

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])

Tip

If you wish, compress your manpage with gzip /usr/local/man/man1/boss.1.

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.

Getting Fancier

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 gzipped 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.

Printing Manpages

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.

Hacking the Hack

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.

See Also

  • man manpath

  • man 7 groff (the groff formatting commands—look for the Request Short Reference section)

  • man 7 mdoc (a mini-tutorial that includes a template for creating manpages)

Get the Most Out of Manpages

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.

Finding Installed Manpages

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
#

Tip

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.

Navigational Tricks

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.

Tip

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.

Table 9-2. less navigation keys

Key

Behavior

Enter

Scrolls down one line

y

Scrolls up one line (think “yikes, I missed it!”)

Spacebar

Scrolls down one page

b

Scrolls up (back) one page

g

Goes to the beginning of the manpage

q

Quits the pager (so you don’t have to read the whole manpage)

Customizing less

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.

Searching Text

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.

Tip

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.

See Also

  • manpath

  • man man

  • man makewhatis

  • man less

Apply, Understand, and Create Patches

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.

Finding Differences

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.

Tip

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.

Applying Patches

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.

Creating Patches

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.

Revision Control

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?

See Also

Display Hardware Information

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.

Viewing Boot Messages

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.

Viewing Resource Information

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.

Gathering Interface Statistics

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     -     -

Viewing Kernel Environment

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.

See Also

  • man dmesg

  • man devinfo

  • man netstat

  • man kenv

Determine Who Is on the 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.

Tip

For the experienced hacker, the output from these commands may suggest interesting scripting possibilities.

Who’s on First?

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 virtual terminals 1 and 5. dru has also logged in over the first pseudoterminal (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)

Tip

If you’re just interested in that first line of output, use uptime.

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] .

When Did That Happen?

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

Details, Details

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.

Tip

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"

See Also

  • man users

  • man who

  • man w

  • man lastlogin

  • man last

  • man lastcomm

Spelling Bee

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?

Quick Spellcheck

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

Tip

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

Creating a Dictionary or Thesaurus

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

Tip

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.

Improved Dictionary

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.

Become a Crossword Champion

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 ..

See Also

Leave on Time

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.

Don’t Forget to Leave

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] .

Creating Terminal Sticky Notes

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.

Saving Your Schedule

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.

See Also

  • man leave

  • man tcsh

Run Native Java Applications

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.

Tip

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.

Choosing Which Java Port to Install

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.

Tip

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.

Tip

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

Running Java Applications

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.

Standalone Java Applications

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

Javavmwrapper

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.

Applets

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.

Tip

If you’re using a Linux web browser under emulation, install the plug-in from one of the Linux Java versions.

Servlets

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.

Java WebStart

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.

See Also

Rotate Your Signature

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.

If Your Mail Program Supports a Pipe

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.

Pipeless Signature Rotation

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 echoes 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.

Hacking the Hack

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.

See Also

  • man fortune

Useful One-Liners

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.

Simultaneously Download and Untar

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.

When Did I Change That File?

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 awkward 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.

Finding Symlinks

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.

Making cron More User-Friendly

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.

See Also

  • man tail

  • man tar

  • man cut

  • man awk

Fun with X

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.

Seeing Console Messages

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] ).

Managing Your Clipboard

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.

Sending Pop-up Messages

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.

Understanding X authorization

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 sshed 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.

Taking Screenshots

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.

See Also

  • man xconsole

  • man xclipboard

  • man xauth

  • man xwd

  • man xwud

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.197.212