The series continues in Learning the Terminal in Mac OS X, Configuring Email from the Mac OS X Terminal, Customizing the Mac OS X Terminal, and Synchronizing Drives with Cron and the Mac OS X Terminal.
However, none of the first three parts of the series will work in Mac OS X 10.2 (Jaguar) or newer. Jaguar brought several major changes to the OS that require significant changes to the procedure. I'll be posting Jaguar compatible updates to these articles shortly.
In Part 1of this series, you learned how to reschedule default system
cron jobs by modifying the system
crontab. Here in Part 2, I'll show you how to configure
cron to email you a report each time it runs one of these jobs.
First, let's take another look at the pertinent lines in
/etc/crontab. Since you only want to look at the file and not modify it, you don't need to use a text editor like
pico. Instead, to only display short files like this, use the
cat utility, which dumps the entire text file into your window and exits:
[localhost:~] chris% cat /etc/crontab
You might notice a couple of interesting things about this command line. First, since the permissions for
/etc/crontab allow anyone to read it (but only root to modify it), using
sudo is not necessary.
Second, this command line allows you to access a file in a directory other than your working directory by specifying, in this case, the full (or absolute) pathname to that file. (You didn't first
/etc to open
crontab, as you did in Part 1.) An absolute path describes the directory hierarchy from the very top of the filesystem (the root directory or "/"), down to the file.
Finally, because some of the
crontab lines might be too long for your window, you'll need to widen the window by dragging its lower right corner to the right until all lines fit without wrapping.
Look now at the line specifying the daily
cron job, which, depending on how you configured the time segment in Part 1, begins something like this:
15 17 * * * root sh /etc/daily ...
Following the first five time fields is the user field. In this case the user field tells
cron to run the job as if "root" were doing it. This is necessary here because these maintenance procedures require the full access to the system allowed to the root account.
Following the user field is the sixth and final field, which specifies the actual command for
cron to execute. The heart of the command,
sh /etc/daily, tells
cron to use
sh, or the Bourne shell, to run the shell script called "daily," found in the
A shell script is a file holding a series of command lines that can be batch-executed by the shell. Much like an AppleScript, a shell script allows you to create and save long automated procedures that you can run at any time, using a single command. The
/etc/daily shell script was written for the Bourne shell, which uses command syntax more apt for shell scripting than the
tcsh shell you've been using.
The entire daily
cron command line, then, looks like this:
sh /etc/daily 2>&1 | tee /var/log/daily.out | mail -s "`hostname` daily output" root
cron, in fact, uses the Bourne shell by default to execute its
crontab commands, so this command wouldn't work if you ran it manually using the
tcsh shell. For the purpose of this article, though, you won't need to modify this command. You won't need to fully understand it either, but this breakdown will give you a general idea of what it does:
sh /etc/daily 2>&1 |
/etc/daily shell script using the Bourne shell, and send its output and any of its error messages on to the next command.
tee /var/log/daily.out |
Write the input from the previous command to a file and also pass it on to the next command. (That's right -- you can always see the results of the latest daily
cron job by viewing
mail -s "`hostname` daily output" root
|This is the place for your questions and comments as you work with Mac OS X's Terminal application.|
Using the input from the previous command as the body, create an email message with the subject "localhost daily out" and send it to root. This, then, is the command that starts the
cron report's journey on its way to your mailbox.
The first step in getting the reports delivered is to direct them to your mailbox, instead of root's. To do this, you could conceivably replace "root" in this command with your account name, but wouldn't it would be simpler if you could just tell the system to redirect all mail addressed to root to your mailbox instead? By using a
.forward file, you can do just that.
.forward file is just a text file containing nothing but the name of the account to which you want the mail forwarded (in this case, your account name). Once the
.forward file is placed in the home directory of the original addressee (in this case, root), the mail gets forwarded as expected.
By default, the Mac OS X root home directory already contains a
.forward file, but this one redirects mail not to another user, but into thin air. This happens because instead of an account name, root's
.forward file contains the pathname
/dev/null, which is the location of a Unix black hole. Streams of data directed to
/dev/null, mail messages included, simply disappear. Since OS X's designers figure most users won't be accessing root's mail, they used this method to ensure mail doesn't pile up at the door while no one's home, eventually filling up your hard disk.
Let's get back to Terminal, then, to edit root's
.forward file. You've probably already noticed that there is no "root" directory in
/Users -- so where is root's home? The easiest way to find any user's home directory is by using the
~ shortcut (for home directory), along with the account name. Therefore, to change your working directory to root's home directory, enter this:
[localhost:~] chris% cd ~root [localhost:~root] chris%
Okay, so now you're in
~root, but where is that really? Remember, you can find out with
[localhost:~root] chris% pwd /private/var/root
ls to view the contents of
[localhost:~root] chris% ls Desktop Documents Library
The contents of your
~root directory might look different, but in any case, you still won't see a
.forward file. What happened to it? One clue is the first character of the file's name, which is a dot ("."). An initial dot is the Unix way of marking filesnames as invisible to the shell (and to the Finder as well). But it's easy enough to see such hidden files in the CLI; just use the
-a option flag with
Option flags allow you to modify the behavior of commands. The
-a option flag for
ls to display "all" items in the working directory, including hidden ones (also known as "dot files"). Simply type the
ls command, add a space, and then type the
[localhost:~root] chris% ls -a . .forward .tcsh_history Library .. .nsmbrc Desktop .CFUserTextEncoding .ssh Documents [localhost:~root] chris%
Again, your view might be different, but you will now see
~root/.forward. You'll next want to edit it using
pico. Since this file is owned by root, you'll need to use
sudo as well:
[localhost:~root] chris% sudo pico .forward
First, delete the file's single line by pressing control + K. Next, type in your account name (the name that's just before the "%" in the prompt; "chris" in this case):
As you learned in Part 1, save the file with control + O, press return to confirm the name, and then press control + X to exit
pico. You're done with the
The next step in the procedure involves getting the mail transfer agent
sendmail to launch successfully when beckoned by the mail user agent
Mail user agents (MUAs) are the kinds of applications that allow you to personally send, receive, and otherwise work with your email messages. Outlook, Eudora, and Mac OS X's Mail application are other familiar examples of MUAs.
Mail transfer agents (MTAs), on the other hand, are the not-so-familiar applications that receive the messages from the MUA and pass them on to other users on the same machine, or to MTAs on other machines for ultimate delivery to users elsewhere. The
sendmail MTA included with OS X is one of the most popular, used on servers large and small across the Internet.
Since you are not running your own mail server at this point, you don't need
sendmail to be running at all times. Instead, you only need to ensure that
sendmail launches when invoked by
cron reports. Used this way,
sendmail quits itself once delivery is made.
sendmail to successfully launch, however, one issue needs to be "fixed" on your system. As a security measure,
sendmail will not run with OS X's default permissions (termed "privileges" in the Finder), namely those for the root directory.
This fix involves one simple change: eliminating write privileges for the group assigned to the
root directory. The CLI makes it very easy to view and change the various permission settings for any item, but the procedures are still too involved to detail here. (Of course, Mac OS X: The Missing Manual does include an in-depth look at permissions and the CLI.)
Instead, I'll zero in on the single command line required to get
sudo chmod g-w /
Since you're modifying the settings for a root-owned directory, the command line starts with
sudo. Next comes the
chmod command, for "change (file) modes." File modes are the settings that specify whether an item can be read or written to, for example, and by which kind of user -- the owner of the item, its group, or any user of the machine. (These settings correspond, of course, with the Privileges settings that are accessible via Finder's Inspector.)
Following a space are
chmod's "arguments," the first of which specifies the modes to be changed (option flags are just another kind of argument, by the way). This argument says to take the group ("
g") and remove ("
-") its permission to write ("
w") to the file or directory specified in the next argument (again followed by a space), which in this case is the root directory, ("
Your next step, then, is to run the command line:
[localhost:~] chris% sudo chmod g-w /
Once you do,
sendmail should work fine. However, you should know that Mac OS X upgrade installers and some application installers change the root directory back to group-writable, so you'll need to run the
chmod command line whenever this happens.
To test everything so far, try sending mail from the CLI. Use the
[localhost:~] chris% mail root Subject:
You're now working inside the
tcsh shell prompts until you exit
After a few moments, check your mail by entering the
[localhost:~] chris% mail No mail for chris
However, once it arrives you'll see something like this:
[[localhost:~] chris% mail Mail version 8.1 6/6/93. Type ? for help. "/var/mail/chris": 1 message 1 new >N 1 chris Sat Jan 5 15:30 13/374 "Test" &
You're back in the
&" prompt to have a look:
Message 1: From chris Sat Jan 5 15:30:01 2002 Date: Sat, 5 Jan 2002 15:30:00 -0800 (PST) From: Chris Stone <chris> To: root Subject: Test This is only a test. & q Saved 1 message in mbox [localhost:~] chris%
As you can see, the test message stays in your local Unix mailbox when you quit mail. Note that this and any other messages there will disappear as a result of the following procedure. However, if this tutorial is new to you, it's very unlikely that you have other messages there anyway. (Of course, your POP and IMAP mail will stay safe and sound.)
You're now ready to set up your GUI Mail application so it can access your local Unix mailbox. Since you will be modifying the folder in which Mail stores its mail,
~/Library/Mail, you should first make a backup of it to, say, your Documents folder:
[localhost:~] chris% cp -R Library/Mail/ Documents/Mail
Here are some important points about this command line:
cprequires you to use its
-Roption flag (for "recursive").
/in relative pathnames.)
Documents/Mail, doesn't specify the directory in which you would like
Library/Mail/to go, but the desired new relative pathname of the copied directory.
Something else you should know about
cp is that it does not properly copy files with resource forks, so you should never use it for that. You'll never have a problem copying Unix and Cocoa applications and related files, which don't contain resource forks, but if you are unsure, use the Finder to copy (or have a look at Mac OS X: The Missing Manual for an explanation of using CpMac, which does handle resource forks reliably).
The next step is to make the directory that Mail requires before it can create a Unix mail account. The directory must exist in
~/Library/Mail/ and be named "
UNIX:@". To create a directory from the command line, use the
mkdir command, followed by a space and the name of the new directory.
However, if there is no
~/Library, the command will return an error. To prevent this possibility, use
-p option flag, which will create any intermediate directories for you if they are missing.
[localhost:~] chris% mkdir -p Library/Mail/UNIX:@
Next you'll need to open Mail and create a Unix mail account, which requires just a few simple steps:
Sure, you can just double-click its icon to open it in the Finder, but since you're in Terminal anyway, how about opening it from there? To do so, just use the
open command (don't forget to include the normally-hidden extension at the end):
[localhost:~] chris% open /Applications/Mail.app
Mail launches immediately, just as if you had opened it from the Finder.
If you've never used Mail before and have no email account info entered in your System Preferences, you'll be prompted to set up an initial account. At a minimum, you'll need to enter an email address, so enter anything you would like; it won't affect the setup of your Unix mail account.
You can safely click through the other prompts for server and other info, and to import mail from other applications. None of this is needed for the task at hand.
From Mail's Mail menu, select Preferences, and then click the Accounts icon. In the Accounts pane, click Create Account. To configure the account, you'll at least need to select the account type (Unix Account), enter a description (Local), and enter something -- anything, really -- in the SMTP Host field.
Of course, if you need to set up a bona fide Unix account, all of these fields mean a great deal. However, for the purpose of only accessing your local Unix mail, this is all you need to configure:
If you are already using Mail to check your regular POP and IMAP accounts, this additional account will not affect those in any way, except that new mail from your Unix account will show up in your default inbox. Of course, if you would like, you could create a new mailbox and a rule to have the incoming
cron reports be placed there instead.
Now that everything's in place, you can perform a test. Send a new mail message to root:
[localhost:~] chris% mail root Subject: Test 2 This is only a test, again. . EOT [localhost:~] chris%
Switch to Mail, and then click Get Mail until you see the message has arrived in your Inbox:
If you see the test message in your inbox, then you're done. The next time
cron runs one of the maintenance jobs, you'll see the report in your inbox as well. For example, the daily
cron job report will look something like this:
Now that these regular reports will be coming in, you'll probably want to be able to understand them. In Part 3, you'll get a closer look at the scripts themselves to learn how to read the reports they generate.
Also in Part 3, I'll show how a Macintosh with a persistent Internet connection can send its reports to any email address. Until then, keep checking to see that you're receiving the reports as expected, and always feel free to submit your comments or questions to our TalkBack section.
I'd like to thank Scott Gever for his techincal help with this series.
Chris Stone is a Senior Macintosh Systems Administrator for O'Reilly, coauthor of Mac OS X in a Nutshell and contributing author to Mac OS X: The Missing Manual, which provides over 40 pages about the Mac OS X Terminal.
Return to the Mac DevCenter.
Copyright © 2009 O'Reilly Media, Inc.