Configuring Linux Mail Servers with Sendmail


Email is an important part of any Web site you create. In a home environment, a free web based email service may be sufficient, but if you are running a business, then a dedicated mail server will probably be required.

This chapter will show you how to use sendmail to create a mail server that will relay your mail to a remote user’s mailbox or incoming mail to a local mail box. You’ll also learn how to retrieve and send mail via your mail server using a with mail client such as Outlook Express or Evolution.

Configuring Sendmail

One of the tasks in setting up DNS for your domain ( is to use the MX record in the configuration zone file to state the hostname of the server that will handle the mail for the domain. The most popular Unix mail transport agent is sendmail, but others, such as postfix and qmail, are also gaining popularity with Linux. The steps used to convert a Linux box into a sendmail mail server will be explained here.

How Sendmail Works

As stated before, sendmail can handle both incoming and outgoing mail for your domain. Take a closer look.
Incoming Mail

Usually each user in your home has a regular Linux account on your mail server. Mail sent to each of these users ( eventually arrives at your mail server and sendmail then processes it and deposits it in the mailbox file of the user’s Linux account.

Mail isn’t actually sent directly to the user’s PC. Users retrieve their mail from the mail server using client software, such as Microsoft’s Outlook or Outlook Express, that supports either the POP or IMAP mail retrieval protocols.

Linux users logged into the mail server can read their mail directly using a text-based client, such as mail, or a GUI client, such as Evolution. Linux workstation users can use the same programs to access their mail remotely.

Outgoing Mail

The process is different when sending mail via the mail server. PC and Linux workstation users configure their e-mail software to make the mail server their outbound SMTP mail server.

If the mail is destined for a local user in the domain, then sendmail places the message in that person’s mailbox so that they can retrieve it using one of the methods above.

If the mail is being sent to another domain, sendmail first uses DNS to get the MX record for the other domain. It then attempts to relay the mail to the appropriate destination mail server using the Simple Mail Transport Protocol (SMTP). One of the main advantages of mail relaying is that when a PC user A sends mail to user B on the Internet, the PC of user A can delegate the SMTP processing to the mail server.

Note: If mail relaying is not configured properly, then your mail server could be commandeered to relay spam. Simple sendmail security will be covered later.

Sendmail Macros

When mail passes through a sendmail server the mail routing information in its header is analyzed, and sometimes modified, according to the desires of the systems administrator. Using a series of highly complicated regular expressions listed in the /etc/mail/ file, sendmail inspects this header and then acts accordingly.

In recognition of the complexity of the /etc/mail/ file, a much simpler file named /etc/ was created, and it contains more understandable instructions for systems administrators to use. These are then interpreted by a number of macro routines to create the file. After editing, you must always run the macros and restart sendmail for the changes to take effect.

Each directive starts with a keyword, such as DOMAIN, FEATURE, or OSTYPE, followed by a subdirective and in some cases arguments. A typical example is.

As stated before, sendmail can handle both incoming and outgoing mail for your domain. Take a closer look.

FEATURE(`virtusertable’,`hash -o /etc/mail/virtusertable.db’)dnl

The keywords usually define a subdirectory of /usr/share/sendmail-cf in which the macro may be found and the subdirective is usually the name of the macro file itself. So in the example, the macro name is /usr/share/sendmail-cf/feature/virtusertable.m4, and the instruction `\ hash -o /etc/mail/virtusertable.db’ is being passed to it.

Notice that sendmail is sensitive to the quotation marks used in the m4 macro directives. They open with a grave mark and end with a single quote.


Some keywords, such as define for the definition of certain sendmail variables and MASQUERADE_DOMAIN, have no corresponding directories with matching macro files. The macros in the /usr/share/sendmail-cf/m4 directory deal with these.

Once you finish editing the file, you can then execute the make command while in the /etc/mail directory to regenerate the new file.

[root@bigboy tmp]# cd /etc/mail
[root@bigboy mail]# make

If there have been no changes to the files in /etc/mail since the last time make was run, then you’ll get an error like this:

[root@bigboy mail]# make
make: Nothing to be done for `all’.
[root@bigboy mail]#

The make command actually generates the file using the m4 command. The m4 usage is simple, you just specify the name of the macro file as the argument, in this case, and redirect the output, which would normally go to the screen, to the file with the ">" redirector symbol.

[root@bigboy tmp]# m4 /etc/mail/ > /etc/mail/

I’ll discuss many of the features of the file later in the chapter.
Installing Sendmail

Most RedHat and Fedora Linux software products are available in the RPM format. You will need to make sure that the sendmail, sendmail-cf, and m4 software RPMs are installed. (Chapter 6, "Installing RPM Software", will tell you how.) When searching for the RPMs, remember that the filename usually starts with the software package name by a version number, as in sendmail-8.12.10-1.1.1.i386.rpm.
Starting Sendmail

You can use the chkconfig command to get sendmail configured to start at boot:

[root@bigboy tmp]# chkconfig sendmail on

To start, stop, and restart sendmail after booting, use

[root@bigboy tmp]# service sendmail start
[root@bigboy tmp]# service sendmail stop
[root@bigboy tmp]# service sendmail restart

Remember to restart the sendmail process every time you make a change to the configuration files for the changes to take effect on the running process. You can also test whether the sendmail process is running with the pgrep command:

[root@bigboy tmp]# pgrep sendmail

You should get a response of plain old process ID numbers.

How To Restart Sendmail After Editing Your Configuration Files

In this chapter, you’ll see that sendmail uses a variety of configuration files that require different treatments for their commands to take effect. This little script encapsulates all the required post configuration steps.

cd /etc/mail
/etc/init.d/sendmail restart

It first runs the make command, which creates a new file from the file and compiles supporting configuration files in the /etc/mail directory according to the instructions in the file /etc/mail/Makefile. It then generates new e-mail aliases with the newaliases command, (this will be covered later), and then restarts sendmail.

Use this command to make the script executable.

chmod 700 filename

You’ll need to run the script each time you change any of the sendmail configuration files described in the sections to follow.

The line in the script that restarts sendmail is only needed if you have made changes to the /etc/mail/ file, but I included it so that you don’t forget. This may not be a good idea in a production system.

Note: When sendmail starts, it reads the file for its configuration. is a more user friendly configuration file and really is much easier to fool around with without getting burned. The file is located in different directories depending on the version of RedHat you use. The /etc/ file is used for versions up to 7.3, and /etc/mail/ is used for versions 8.0 and higher and Fedora Core.

The /etc/mail/ File

You can define most of sendmail’s configuration parameters in the /etc/mail/ file, which is then used by the m4 macros to create the /etc/mail/ file. Configuration of the file is much simpler than configuration of, but it is still often viewed as an intimidating task with its series of structured directive statements that get the job done. Fortunately, in most cases you won’t have to edit this file very often.

How to Put Comments in

In most Linux configuration files a # symbol is used at the beginning of a line convert it into a comment line or to deactivate any commands that may reside on that line.

The file doesn’t use this character for commenting, but instead uses the string "dnl". Here are some valid examples of comments used with the configuration file:

* These statements are disabled by dnl commenting.

dnl DAEMON_OPTIONS(`Port=smtp,Addr=, Name=MTA’)
dnl # DAEMON_OPTIONS(`Port=smtp,Addr=, Name=MTA’)

* This statement is incorrectly disabled:

# DAEMON_OPTIONS(`Port=smtp,Addr=, Name=MTA’)

* This statement is active:

DAEMON_OPTIONS(`Port=smtp,Addr=, Name=MTA’)

Configuring DNS for sendmail

Remember that you will never receive mail unless you have configured DNS for your domain to make your new Linux box mail server the target of the DNS domain’s MX record. See either Chapter 18, "Configuring DNS", or Chapter 19, "Dynamic DNS", for details on how to do this.
Configure Your Mail Server’s Name In DNS

You first need to make sure that your mail server’s name resolves in DNS correctly. For example, if your mail server’s name is bigboy and it you intend for it to mostly handle mail for the domain, then must correctly resolve to the IP address of one of the mail server’s interfaces. You can test this using the host command:

[root@smallfry tmp]# host has address
[root@smallfry tmp]#

You will need to fix your DNS server’s entries if the resolution isn’t correct.

Configure The /etc/resolv.conf File

The sendmail program expects DNS to be configured correctly on the DNS server. The MX record for your domain must point to the IP address of the mail server.

The program also expects the files used by the mail server’s DNS client to be configured correctly. The first one is the /etc/resolv.conf file in which there must be a domain directive that matches one of the domains the mail server is expected to handle mail for.

Finally, sendmail expects a nameserver directive that points to the IP address of the DNS server the mail server should use to get its DNS information.

For example, if the mail server is handling mail for and the IP address of the DNS server is, there must be directives that look like this:


An incorrectly configured resolv.conf file can lead to errors when running the m4 command to process the information in your file.

WARNING: local host name (smallfry) is not qualified; fix $j in config file

The /etc/hosts File

The /etc/hosts file also is used by DNS clients and also needs to be correctly configured. Here is a brief example of the first line you should expect to see in it: localhost.localdomain localhost bigboy

The entry for must always be followed by the fully qualified domain name (FQDN) of the server. In the case above it would be Then you must have an entry for localhost and localhost.localdomain. Linux does not function properly if the entry in /etc/hosts doesn’t also include localhost and localhost.localdomain. Finally you can add any other aliases your host may have to the end of the line.
How To Configure Linux Sendmail Clients

All Linux mail clients in your home or company need to know which server is the mail server. This is configured in the file by setting the SMART_HOST statement to include the mail server. In the example below, the mail server has been set to, the mail server for the domain.


If you don’t have a mail server on your network, you can either create one, or use the one offered by your ISP.

Once this is done, you need to process the file and restart sendmail. To do this, run the restarting script we from earlier in the chapter.

If the sendmail server is a Linux server, then the /etc/hosts file will also have to be correctly configured too.

Converting From a Mail Client to a Mail Server

All Linux systems have a virtual loopback interface that lives only in memory with an IP address of As mail must be sent to a target IP address even when there is no NIC in the box, sendmail therefore uses the loopback address to send mail between users on the same Linux server. To become a mail server, and not a mail client, sendmail needs to be configured to listen for messages on NIC interfaces as well.

1) Determine which NICs sendmail is running on. You can see the interfaces on which sendmail is listening with the netstat command. Because sendmail listens on TCP port 25, you use netstat and grep for 25 to see a default configuration listening only on IP address (loopback):

[root@bigboy tmp]# netstat -an | grep :25 | grep tcp
tcp 0 0* LISTEN
[root@bigboy tmp]#

2) Edit to make sendmail listen on all interfaces. If sendmail is listening on the loopback interface only, you should comment out the daemon_options line in the /etc/mail/ file with dnl statements. It is also good practice to take precautions against spam by not accepting mail from domains that don’t exist by commenting out the accept_unresolvable_domains feature too. See the fourth and next to last lines in the example.

dnl This changes sendmail to only listen on the loopback
dnl device and not on any other network
dnl devices. Comment this out if you want
dnl to accept email over the network.
dnl DAEMON_OPTIONS(`Port=smtp,Addr=, Name=MTA’)

dnl We strongly recommend to comment this one out if you want
dnl to protect yourself from spam. However, the laptop and
dnl users on computers that do
dnl not have 24×7 DNS do need this.
dnl FEATURE(`accept_unresolvable_domains’)dnl
dnl FEATURE(`relay_based_on_MX’)dnl

Note: You need to be careful with the accept_unresolvable_names feature. In the sample network, bigboy the mail server does not accept e-mail relayed from any of the other PCs on your network if they are not in DNS. Chapter 18, "Configuring DNS", shows how to create your own internal domain just for this purpose.

Note: If your server has multiple NICs and you want it to listen to one of them, then you can uncomment the localhost DAEMON_OPTIONS entry and add another one for the IP address of the NIC on which to wish to accept SMTP traffic.

3) Comment out the SMART_HOST Entry in The mail server doesn’t need a SMART_HOST entry in its file. Comment this out with a dnl at the beginning.

dnl define(`SMART_HOST’,`’)

4) Regenerate the file, and restart sendmail. Again, you can do this with the restart script from the beginning of the chapter.

5) Make sure sendmail is listening on all interfaces (

[root@bigboy tmp]# netstat -an | grep :25 | grep tcp
tcp 0 0* LISTEN
[root@bigboy tmp]#

You have now completed the first phase of converting your Linux server into a sendmail server by enabling it to listen to SMTP traffic on its interfaces. The following sections will show you how to define what type of mail it should handle and the various ways this mail can be processed.

A General Guide To Using The File

The file can seem jumbled. To make it less cluttered I usually create two easily identifiable sections in it with all the custom commands I’ve ever added.

The first section is near the top where the FEATURE statements usually are, and the second section is at the very bottom.

Sometimes sendmail will archive this file when you do a version upgrade. Having easily identifiable modifications in the file will make post upgrade reconfiguration much easier. Here is a sample:

dnl ***** Customised section 1 start *****
dnl ***** Customised section 1 end *****

The /etc/mail/relay-domains File

The /etc/mail/relay-domains file is used to determine domains from which it will relay mail. The contents of the relay-domains file should be limited to those domains that can be trusted not to originate spam. By default, this file does not exist in a standard RedHat / Fedora install. In this case, all mail sent from and not destined for this mail server will be forwarded:

One disadvantage of this file is that controls mail based on the source domain only, and source domains can be spoofed by spam e-mail servers. The /etc/mail/access file has more capabilities, such as restricting relaying by IP address or network range and is more commonly used. If you delete /etc/mail/relay-domains, then relay access is fully determined by the /etc/mail/access file.

Be sure to run the restart sendmail script from the beginning of the chapter for these changes to take effect.
The /etc/mail/access File

You can make sure that only trusted PCs on your network have the ability to relay mail via your mail server by using the /etc/mail/access file. That is to say, the mail server will relay mail only for those PCs on your network that have their e-mail clients configured to use the mail server as their outgoing SMTP mail server. (In Outlook Express, you set this using: Tools>Accounts>Properties>Servers)

If you don’t take the precaution of using this feature, you may find your server being used to relay mail for spam e-mail sites. Configuring the /etc/mail/access file will not stop spam coming to you, only spam flowing through you.

The /etc/mail/access file has two columns. The first lists IP addresses and domains from which the mail is coming or going. The second lists the type of action to be taken when mail from these sources or destinations is received. Keywords include RELAY, REJECT, OK (not ACCEPT), and DISCARD. There is no third column to state whether the IP address or domain is the source or destination of the mail, sendmail assumes it could be either and tries to match both. All other attempted relayed mail that doesn’t match any of the entries in the /etc/mail/access file, sendmail will reject. Despite this, my experience has been that control on a per e-mail address basis is much more intuitive via the /etc/mail/virtusertable file.

The sample file that follows allows relaying for only the server itself (, localhost), two client PCs on your home 192.168.1.X network, everyone on your 192.168.2.X network, and everyone passing e-mail through the mail server from servers belonging to Remember that a server will be considered a part of only if its IP address can be found in a DNS reverse zone file:

localhost.localdomain RELAY
192.168.2 RELAY RELAY

You’ll then have to convert this text file into a sendmail readable database file named /etc/mail/access.db. Here are the commands you need:

[root@bigboy tmp]# cd /etc/mail
[root@bigboy mail]# make

The sendmail restart script we configured at the beginning of the chapter does this for you too.

Remember that the relay security features of this file may not work if you don’t have a correctly configured /etc/hosts file.

The /etc/mail/local-host-names File

When sendmail receives mail, it needs a way of determining whether it is responsible for the mail it receives. It uses the /etc/mail/local-host-names file to do this. This file has a list of hostnames and domains for which sendmail accepts responsibility. For example, if this mail server was to accept mail for the domains and another-site then the file would look like this:

In this case, remember to modify the MX record of the DNS zonefile point to Here is an example (Remember each "." is important):

; Primary Mail Exchanger for MX 10

Which User Should Really Receive The Mail?

After checking the contents of the virtusertable, sendmail checks the aliases files to determine the ultimate recipient of mail.
The /etc/mail/virtusertable file

The /etc/mail/virtusertable file contains a set of simple instructions on what to do with received mail. The first column lists the target email address and the second column lists the local user’s mail box, a remote email address, or a mailing list entry in the /etc/aliases file to which the email should be forwarded.

If there is no match in the virtusertable file, sendmail checks for the full email address in the /etc/aliases file. webmasters marc paul paul error:nouser User unknown

In this example, mail sent to:

* will go to local user (or mailing list) webmasters, all other mail to will go to local user marc.
* sales at will go to the sales department at
* paul and finance at goes to local user (or mailing list) paul

All other users at receive a bounce back message stating "User unknown".

After editing the /etc/mail/virtusertable file, you have to convert it into a sendmail-readable database file named /etc/mail/virtusertable.db with two commands:

[root@bigboy tmp]# cd /etc/mail
[root@bigboy mail]# make

If these lines look like you’ve seen them before, you have: They’re in your all-purpose sendmail restart script.

The /etc/aliases File

You can think of the /etc/aliases file as a mailing list file. The first column has the mailing list name (sometimes called a virtual mailbox), and the second column has the members of the mailing list separated by commas.

To start, sendmail searches the first column of the file for a match. If there is no match, then sendmail assumes the recipient is a regular user on the local server and deposits the mail in their mailbox.

If it finds a match in the first column, sendmail notes the nickname entry in the second column. It then searches for the nickname again in the first column to see if the recipient isn’t on yet another mailing list.

If sendmail doesn’t find a duplicate, it assumes the recipient is a regular user on the local server and deposits the mail in their mailbox.

If the recipient is a mailing list, then sendmail goes through the process all over again to determine if any of the members is on yet another list, and when it is all finished, they all get a copy of the e-mail message.

In the example that follows, you can see that mail sent to users bin, daemon, lp, shutdown, apache, named, and so on by system processes will all be sent to user (or mailing list) root. In this case, root is actually an alias for a mailing list consisting of user marc and

# Basic system aliases — these MUST be present.
mailer-daemon: postmaster
postmaster: root

# General redirections for pseudo accounts.
bin: root
daemon: root

abuse: root
# trap decode to catch security attacks
decode: root

# Person who should get root’s mail
root: marc,

Notice that there are no spaces between the mailing list entries for root: You will get errors if you add spaces.

Note: The default /etc/aliases file installed with RedHat / Fedora has the last line of this sample commented out with a #, you may want to delete the comment and change user marc to another user. Also after editing this file, you’ll have to convert it into a sendmail readable database file named /etc/aliases.db. Here is the command to do that:

[root@bigboy tmp]# newaliases

In this simple mailing list example, mail sent to root actually goes to user account marc and Because aliases can be very useful, here are a few more list examples for your /etc/aliases file.

* Mail to "" goes to users "peter", "paul" and "mary".

# Directors of my SOHO company
directors: peter,paul,mary

* Mail sent to "" goes to users "grandma", "brother" and "sister"

# My family
family: grandma,brother,sister

* Mail sent to admin-list gets sent to all the users listed in the file /home/mailings/admin-list.

# My mailing list file
admin-list: ":include:/home/mailings/admin-list"

The advantage of using mailing list files is that the admin-list file can be a file that trusted users can edit, user root is only needed to update the aliases file. Despite this, there are some problems with mail reflectors. One is that bounce messages from failed attempts to broadcast go to all users. Another is that all subscriptions and unsubscriptions have to be done manually by the mailing list administrator. If either of these are a problem for you, then consider using a mailing list manager, such as majordomo.

One important note about the /etc/aliases file: By default your system uses sendmail to mail system messages to local user root. When sendmail sends e-mail to a local user, the mail has no To: in the e-mail header. If you then use a mail client with a spam mail filtering rule to reject mail with no To: in the header, such as Outlook Express or Evolution, you may find yourself dumping legitimate mail.

To get around this, try making root have an alias for a user with a fully qualified domain name, this forces sendmail to insert the correct fields in the header; for example:

# Person who should get root’s mail

Sendmail Masquerading Explained

If you want your mail to appear to come from and not, then you have two choices:

* Configure your email client, such as Outlook Express, to set your email address to (I’ll explain this in the "Configuring Your POP Mail Server" section.).
* Set up masquerading to modify the domain name of all traffic originating from and passing trough your mail server.

Configuring masquerading

In the DNS configuration, you made bigboy the mail server for the domain You now have to tell bigboy in the sendmail configuration file that all outgoing mail originating on bigboy should appear to be coming from; if not, based on our settings in the /etc/hosts file, mail will appear to come from This isn’t terrible, but you may not want your Web site to be remembered with the word "mail" in front of it. In other words you may want your mail server to handle all email by assigning a consistent return address to all outgoing mail, no matter which server originated the email.

You can solve this by editing your configuration file and adding some masquerading commands and directives:


The result is that:

* The MASQUERADE_AS directive makes all mail originating on bigboy appear to come from a server within the domain by rewriting the email header.
* The MASQUERADE_DOMAIN directive makes mail relayed via bigboy from all machines in the and localdomain domains appear to come from the MASQUERADE_AS domain of Using DNS, sendmail checks the domain name associated with the IP address of the mail relay client sending the mail to help it determine whether it should do masquerading or not.
* FEATURE masquerade_entire_domain makes sendmail masquerade servers named *, and * as In other words, mail from would be masqueraded as If this wasn’t selected, then only servers named and would be masqueraded. Use this with caution when you are sure you have the necessary authority to do this.
* FEATURE allmasquerade makes sendmail rewrite both recipient addresses and sender addresses relative to the local machine. If you cc: yourself on an outgoing mail, the other recipient sees a cc: to an address he knows instead of one on localhost.localdomain.

Note: Use FEATURE allmasquerade with caution if your mail server handles email for many different domains and the mailboxes for the users in these domains reside on the mail server. The allmasquerade statement causes all mail destined for these mailboxes to appear to be destined for users in the domain defined in the MASQUERADE_AS statement. In other words, if MASQUERADE_AS is and you use allmasquerade, then mail for enters the correct mailbox but sendmail rewrites the To:, making the e-mail appear to be sent to originally.

* FEATURE always_add_domain always masquerades email addresses, even if the mail is sent from a user on the mail server to another user on the same mail server.
* FEATURE masquerade_envelope rewrites the email envelope just as MASQUERADE_AS rewrote the header.

Masquerading is an important part of any mail server configuration as it enables systems administrators to use multiple outbound mail servers, each providing only the global domain name for a company and not the fully qualified domain name of the server itself. All email correspondence then has a uniform email address format that complies with the company’s brand marketing policies.

Note: E-mail clients, such as Outlook Express, consider the To: and From: statements as the e-mail header. When you choose Reply or Reply All in Outlook Express, the program automatically uses the To: and From: in the header. It is easy to fake the header, as spammers often do; it is detrimental to e-mail delivery, however, to fake the envelope.

The e-mail envelope contains the To: and From: used by mailservers for protocol negotiation. It is the envelope’s From: that is used when e-mail rejection messages are sent between mail servers.

Testing Masquerading

The best way of testing masquerading from the Linux command line is to use the "mail -v username" command. I have noticed that "sendmail -v username" ignores masquerading altogether. You should also tail the /var/log/maillog file to verify that the masquerading is operating correctly and check the envelope and header of test email received by test email accounts.

Other Masquerading Notes

By default, user "root" will not be masqueraded. To remove this restriction use:


command in /etc/mail/ You can comment this out if you like with a "dnl" at the beginning of the line and running the sendmail start script.

Using Sendmail to Change the Sender’s Email Address

Sometimes masquerading isn’t enough. At times you may need to change not only the domain of the sender but also the username portion of the sender’s e-mail address. For example, perhaps you bought a program for your SOHO office that sends out notifications to your staff, but the program inserts its own address as sender’s address, not that of the IT person.

Web-based CGI scripts tend to run as user apache and, therefore, send mail as user apache too. Often you won’t want this, not only because apache’s e-mail address may not be a suitable, but also because some anti-spam programs check to ensure that the From:, or source e-mail address, actually exists as a real user. If your virtusertable file allows e-mail to only predefined users, then queries about the apache user will fail, and your valid e-mail may be classified as being spam.

With sendmail, you can change both the domain and username on a case-by-case basis using the genericstable feature:

1) Add these statements to your /etc/mail/ file to activate the feature:

FEATURE(`genericstable’,`hash -o /etc/mail/genericstable.db’)dnl

2) Create a /etc/mail/generics-domains file that is just a list of all the domains that should be inspected. Make sure the file includes your server’s canonical domain name, which you can obtain using the command:

sendmail -bt -d0.1 /etc/mail/
/etc/mail/ m4: Cannot open /usr/share/sendmail-cf/m4/cf.m4: No such file or directory
[root@bigboy mail]#

* Sample errors when restarting sendmail

[root@bigboy mail]# service sendmail restart
Shutting down sendmail: [ OK ]
Shutting down sm-client: [FAILED]
Starting sendmail: 554 5.0.0 No local mailer defined
554 5.0.0 QueueDirectory (Q) option must be set
Starting sm-client: [ OK ]
[root@bigboy mail]#

If these errors occur, make sure your m4, sendmail and senmail-cf RPM packages are installed correctly.

Incorrectly Configured /etc/hosts Files

By default, Fedora inserts the hostname of the server between the and the localhost entries in /etc/hosts like this: bigboy localhost.localdomain localhost

Unfortunately in this configuration, sendmail will think that the server’s FQDN is bigboy, which it will identify as being invalid because there is no extension at the end, such as .com or .net. It will then default to sending e-mails in which the domain is localhost.localdomain.

The /etc/hosts file is also important for configuring mail relay. You can create problems if you fail to place the server name in the FDQN for entry. Here sendmail thinks that the server’s FDQN was my-site and that the domain was all of .com. localhost.localdomain localhost (Wrong!!!)

The server would therefore be open to relay all mail from any .com domain and would ignore the security features of the access and relay-domains files I’ll describe later.

As mentioned, a poorly configured /etc/hosts file can make mail sent from your server to the outside world appear as if it came from users at localhost.localdomain and not

Use the sendmail program to send a sample e-mail to someone in verbose mode. Enter some text after issuing the command and end your message with a single period all by itself on the last line, for example:

[root@bigboy tmp]# sendmail -v
test text
test text
.… Connecting to via esmtp…
220 LiteMail v3.02(BFLITEMAIL4A); Sat, 05 Oct 2002 06:48:44 -0400
>>> EHLO localhost.localdomain Hello [], pleased to meet you
250 HELP
>>> MAIL From:
250 … Sender Ok
>>> RCPT To:
250 … Recipient Ok
>>> DATA
354 Enter mail, end with "." on a line by itself
>>> .
250 Message accepted for delivery… Sent (Message accepted for delivery)
Closing connection to
>>> QUIT
[root@bigboy tmp]#

localhost.localdomain is the domain that all computers use to refer to themselves, it is therefore an illegal Internet domain. Consider an example: Mail sent from computer PC1 to PC2 appears to come from a user at localhost.localdomain on PC1 and is rejected. The rejected e-mail is returned to localhost.localdomain. PC2 sees that the mail originated from localhost.localdomain and thinks that the rejected e-mail should be sent to a user on PC2 that may not exist. You end up with an error in /var/log/maillog:

Oct 16 10:20:04 bigboy sendmail[2500]: g9GHK3iQ002500: SYSERR(root): savemail: cannot save rejected email anywhere
Oct 16 10:20:04 bigboy sendmail[2500]: g9GHK3iQ002500: Losing ./qfg9GHK3iQ002500: savemail panic

You may also get this error if you are using a spam prevention program, such as a script based on the PERL module Mail::Audit. An error in the script could cause this type of message too.

Another set of tell tale errors caused by the same problem can be generated when trying to send mail to a user (the example uses root) or creating a new alias database file. (I’ll explain the newaliases command later.)

[root@bigboy tmp]# sendmail -v root
WARNING: local host name (bigboy) is not qualified; fix $j in config file
[root@bigboy tmp]# newaliases
WARNING: local host name (bigboy) is not qualified; fix $j in config file
[root@bigboy tmp]#

An accompanying error in /var/log/maillog log file looks like this:

Oct 16 10:23:58 bigboy sendmail[2582]: My unqualified host name (bigboy) unknown; sleeping for retry

Fighting SPAM

Unsolicited Commercial Email (UCE or SPAM) can be annoying, time consuming to delete and in some cases dangerous when they contain viruses and worms. Fortunately there are ways you can use your mail server to combat SPAM.

Using Public SPAM Blacklists With Sendmail

There are many publicly available lists of known open mail relay servers and spam generating mail servers on the Internet. Some are maintained by volunteers, others are managed by public companies, but in all cases they rely heavily on complaints from spam victims. Some spam blacklists simply try to determine whether the e-mail is coming from a legitimate IP address.

The IP addresses of offenders usually remain on the list for six months to two years. In some cases, to provide additional pressure on the spammers, the blacklists include not only the offending IP address but also the entire subnet or network block to which it belongs. This prevents the spammers from easily switching their servers’ IP addresses to the next available ones on their networks. Also, if the spammer uses a public data center, it is possible that their activities could also cause the IP addresses of legitimate e-mailers to be black listed too. It is hoped that these legitimate users will pressure the data center’s management to evict the spamming customer.

You can configure sendmail to use its dnsbl feature to both query these lists and reject the mail if a match is found. Here are some sample entries you can add to your /etc/ file; they should all be on one line.

* RFC-Ignorant: A valid IP address checker.

FEATURE(`dnsbl’, `’,`"550 Mail from " $&{client_addr} " refused. Rejected for bad WHOIS info on IP of your SMTP server – see"’)

* Easynet: An open proxy list.

FEATURE(`dnsbl’, `’, `"550 5.7.1 ACCESS DENIED to OPEN PROXY SERVER "$&{client_name}" by DNSBL ("’, `’)dnl

* The Open Relay Database: An open mail relay list.

FEATURE(`dnsbl’, `’, `"550 Email rejected due to sending server misconfiguration – see\#why_rejected"’)dnl

* Spamcop: A spammer blacklist.

FEATURE(`dnsbl’, `’, `"450 Mail from " $`’&{client_addr} " refused – see"’)

* Spamhaus: A spammer blacklist.

FEATURE(`dnsbl’,`’,`Rejected – see’)dnl

Be sure to visit the URLs listed to learn more about the individual services.


Once sendmail receives an e-mail message, it hands the message over to procmail, which is the application that actually places the e-mail in user mailboxes on the mail server. You can make procmail temporarily hand over control to another program, such as a spam filter. The most commonly used filter is spamassassin.

spamassassin doesn’t delete spam, it merely adds the word "spam" to the beginning of the subject line of suspected spam e-mails. You can then configure the e-mail filter rules in Outlook Express or any other mail client to either delete the suspect message or store it in a special Spam folder.

Downloading And Installing Spamassassin

Most RedHat and Fedora Linux software products are available in the RPM format. When searching for the RPMs, remember that the filename usually starts with the software package name and is followed by a version number, as in spamassassin-2.60-2.i386.rpm. (For help downloading, see Chapter 6, "Installing RPM Software").
Starting Spamassassin

You can use the chkconfig command to get spamassassin configured to start at boot:

[root@bigboy tmp]# chkconfig –level 35 spamassassin on

To start, stop, and restart spamassassin after booting:

[root@bigboy tmp]# service spamassassin start
[root@bigboy tmp]# service spamassassin stop
[root@bigboy tmp]# service spamassassin restart

Configuring procmail for spamassassin

The /etc/procmailrc file is used by procmail to determine the procmail helper programs that should be used to filter mail. This file isn’t created by default.

spamassassin has a template you can use called /etc/mail/spamassassin/spamassassin-spamc.rc. Copy the template to the /etc directory.

[root@bigboy tmp]# cp /etc/mail/spamassassin/spamassassin-spamc.rc /etc/procmailrc

Configuring Spamassassin

The spamassassin configuration file is named /etc/mail/spamassassin/ A full listing of all the options available in the file can be found in the Linux man pages using the following command:

[root@bigboy tmp]# man Mail::SpamAssassin::Conf

You can customize this fully commented sample configuration file to meet your needs.

# See ‘perldoc Mail::SpamAssassin::Conf’ for
# details of what can be adjusted.

# These values can be overridden by editing
# ~/.spamassassin/ (see spamassassin(1) for details)

# How many hits before a message is considered spam. The lower the
# number the more sensitive it is.

required_hits 5.0

# Whether to change the subject of suspected spam (1=Yes, 0=No)
rewrite_subject 1

# Text to prepend to subject if rewrite_subject is used
subject_tag *****SPAM*****

# Encapsulate spam in an attachment (1=Yes, 0=No)
report_safe 1

# Use terse version of the spam report (1=Yes, 0=No)
use_terse_report 0

# Enable the Bayes system (1=Yes, 0=No)
use_bayes 1

# Enable Bayes auto-learning (1=Yes, 0=No)
auto_learn 1

# Enable or disable network checks (1=Yes, 0=No)
skip_rbl_checks 0
use_razor2 1
use_dcc 1
use_pyzor 1

# Mail using languages used in these country codes will not be marked
# as being possibly spam in a foreign language.
# – english

ok_languages en

# Mail using locales used in these country codes will not be marked
# as being possibly spam in a foreign language.

ok_locales en

Be sure to restart spamassassin for your changes to take effect.

Testing spamassassin

You can test the validity of your file by using the spamassassin command with the –lint option. This will list any syntax problems that may exist. In this example two errors were found and corrected before the command was run again.

[root@bigboy tmp]# spamassassin -d –lint
Created user preferences file: /root/.spamassassin/user_prefs
config: SpamAssassin failed to parse line, skipping: use_terse_report 0
config: SpamAssassin failed to parse line, skipping: auto_learn 1
lint: 2 issues detected. please rerun with debug enabled for more information.
[root@bigboy tmp]# vi /etc/mail/spamassassin/

[root@bigboy tmp]# spamassassin -d –lint
[root@bigboy tmp]

Startup spamassassin

The final steps are to configure spamassassin to start on booting and then to start it.

[root@bigboy tmp]# chkconfig spamassassin on
[root@bigboy tmp]# service spamassassin start
Starting spamd: [ OK ]
[root@bigboy tmp]#

Tuning spamassassin

You can tune the sensitivity of spamassassin to the type of spam you receive by adjusting the required_hits value in the file. This can be made easier by viewing the score spamassassin assigns a message in its header. In most GUI based email clients this can be done by looking at the email’s properties. In this case, a Nigerian email scam spam was detected and given a score of 20.1 and marked as spam.

X-Spam-Status: Yes, score=20.1 required=2.1 tests=DEAR_FRIEND,
* 0.5 FROM_ENDS_IN_NUMS From: ends in numbers
* 0.2 RISK_FREE BODY: Risk free. Suuurreeee….
* 0.4 US_DOLLARS_3 BODY: Mentions millions of $ ($NN,NNN,NNN.NN)
* 0.8 DEAR_FRIEND BODY: Dear Friend? That’s not very dear!
* 2.2 NA_DOLLARS BODY: Talks about a million North American dollars
* 1.8 RCVD_IN_BL_SPAMCOP_NET RBL: Received via a relay in
* [Blocked – see ]
* 1.1 RCVD_IN_SBL RBL: Received via a relay in Spamhaus SBL
* [ listed in]
* 1.4 DNS_FROM_RFC_POST RBL: Envelope sender in
* 1.9 NIGERIAN_BODY3 Message body looks like a Nigerian spam message 3+
* 2.9 NIGERIAN_BODY1 Message body looks like a Nigerian spam message 1+
* 1.4 NIGERIAN_BODY4 Message body looks like a Nigerian spam message 4+
* 1.7 SARE_FRAUD_X5 Matches 5+ phrases commonly used in fraud spam
* 0.5 NIGERIAN_BODY2 Message body looks like a Nigerian spam message 2+
* 1.7 SARE_FRAUD_X3 Matches 3+ phrases commonly used in fraud spam
* 1.7 SARE_FRAUD_X4 Matches 4+ phrases commonly used in fraud spam
* 0.0 MSGID_FROM_MTA_HEADER Message-Id was added by a relay

Limiting your spam fighting efforts to the required_hits value isn’t usually adequate. You will probably need additional spamassassin tools to be more selective and accurate in your tests. This will be covered next.
The Rules du Jour Spamassassin Tool

There are groups of open source developers that create and update customized spamassassin configuration files that make the tool even more effective. They have even made life easier for the harried systems administrator by creating a script named rules_du_jour that, on a daily basis, will automatically download the rules you select.

The rules_du_jour script can be downloaded from its website at which has easy to understand installation instructions, but there are some caveats which need to be explained.
The /etc/rulesdujour/config Configuration File

Rules du Jour’s configuration file located at /etc/rulesdujour/config has four variables that need to be defined. Each must be enclosed in quotation marks.

The first is SA_DIR, which defines the directory in which you have installed spamassassin. The second is MAIL_ADDRESS which defines the address to which Rules du Jour sends its status messages. The third, SA_RESTART, is the command to be used to restart spamassassin each time the rules_du_jour script is run.

The final parameter, TRUSTED_RULESETS, is the most complicated. It is a space delimited list of all the rules you wish to use. A full list can be found on the Rules du Jour website but there isn’t much explanation about what they do and how sensitive each one is to marking email as being spam. Fortunately, you can get this information from the "Rules" section of the Rules Emporium site (

It is important to read the notes for each rule they sometimes have sub-groupings of rules that may more suitable for your needs. For example, the SARE_HTML rule includes all the rules in SARE_HTML0, SARE_HTML1, SARE_HTML2, SARE_HTML3 and SARE_HTML_ENG, but according to Rules Emporium, only SARE_HTML0 has a low degree of false positives.

Here is a sample of a /etc/rulesdujour/config configuration file that has taken advantage of some of the more popular and reliable rules.

# File: /etc/rulesdujour/config

# Script information can be found at:

SA_RESTART="service spamd restart"

Note: The Rules du Jour and Rules Emporium sites use the terms "spam" and "ham" frequently. Spam is unwanted email, while ham is the opposite.
Installing Rules du Jour

Installation is fairly simple, here is how it is done:

1) Download the rules_du_jour script with the wget command, make it executable and place it in the /usr/local/bin directory.

[root@bigboy tmp]# wget
=> `rules_du_jour’
Connecting to||:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 63,448 (62K) [application/octet-stream]

100%[=======================================>] 63,448 79.85K/s

10:58:28 (79.59 KB/s) – `rules_du_jour’ saved [63448/63448]

[root@bigboy tmp]# chmod 700 rules_du_jour
[root@bigboy tmp]# mv rules_du_jour /usr/local/bin

2) Create and edit your /etc/rulesdujour/config configuration file.

[root@bigboy tmp]# mkdir -p /etc/rulesdujour
[root@bigboy tmp]# vi /etc/rulesdujour/config

3) Run the rules_du_jour script, and then run spamassassin in lint mode to test for errors. There should be none.

[root@bigboy tmp]# /usr/local/bin/rules_du_jour
exec: curl -w %{http_code} –compressed -O -R -s -S -z /etc/mail/spamassassin/RulesDuJour/rules_du_jour 2>&1
curl_output: 304


/^\s*#.*(vers?|version|rev|revision)[:\.\s]*[0-9]/i;’ | sort | tail -n 1
[root@bigboy tmp]# spamassassin -d –lint
[root@bigboy tmp]#

4) The final step is to add /usr/local/bin/rules_du_jour to your cron table. In this case, I have just created the file /etc/cron.d/rulesdujour with the following entry:

# Get latest SpamAssassin rules. Runs at 12:23AM every day.
0 23 * * * root /usr/local/bin/rules_du_jour

5) You may have to restart crond to get this configuration to become active

[root@bigboy tmp]# service crond restart
Stopping crond: [ OK ]
Starting crond: [ OK ]
[root@bigboy tmp]#

My experience with Rules du Jour has been very good. Without it, I could only set the required_hits value in the /etc/mail/spamassassin/ file to a relatively insensitive value of 4.5. Anything lower would create too many false positives and valuable mail would be marked as being suspicious. Rules du Jour selectively raises the score of specific types of spam such that I can make the required_hits setting have a very sensitive value of 2.1 with very few false positives.
Using Greylisting

To maximize the effect of their efforts, spammers try to send email as quickly as possible. They take note of the emails that bounce, so that they know which addresses to remove from their lists to make their next mailing more efficient.

When mail servers receive mail too rapidly for them to handle, they can ask the sender to try again later. Spammers often view resending emails to valid addresses as a waste of computing time that could be used to send mail to brand new addresses that belong to faster mail servers. Emails that need to be resent are usually abandoned.

Some emails need reliable delivery to be effective and the senders of these types of messages are willing to resend. These include bank statement notifications, ecommerce purchase confirmations, and subscription newsletters.

In a previous section we saw where spamassassin always rejects emails from blacklisted sources. With greylisting, sources are just asked to resend. One of the most popular greylist mail filter (milter) products is the milter-greylist package which also works seamlessly with spamassassin. It is easy to use and I’ll discuss how can be configured on your mail server.
Downloading and Installing milter-greylist

Installing milter-greylist is relatively simple, but there are a lot of steps. Here’s how to do it:

1. You will have to first install the sendmail-devel software package. Most RedHat and Fedora Linux software products are available in the RPM format. When searching for the RPMs, remember that the filename usually starts with the software package name and is followed by a version number, as in sendmail-devel-8.13.1-2.rpm. (For help downloading, see Chapter 6, "Installing RPM Software").

2. The next step is to download the milter-greylist tar file which you can download from the milter’s website at In this case we download the version 2.0.2 file using the wget command.

[root@bigboy tmp]# wget
=> `milter-greylist-2.0.2.tgz’
Connecting to||:21… connected.
Logging in as anonymous … Logged in!
==> SYST … done. ==> PWD … done.
==> TYPE I … done. ==> CWD /pub/milter-greylist … done.
==> PASV … done. ==> RETR milter-greylist-2.0.2.tgz … done.
Length: 116,459 (114K) (unauthoritative)

100%[================================>] 116,459 71.07K/s

10:48:20 (70.79 KB/s) – `milter-greylist-2.0.2.tgz’ saved [116459]
[root@bigboy tmp]#

3. Now that you have the file, you’ll have to extract the contents using the tar command.

[root@bigboy tmp]# tar -xzvf milter-greylist-2.0.2.tgz

[root@bigboy tmp]#

4. Now enter the newly created milter-greylist directory and compile the package with the configure command. Take a look at the README file before doing this as there may be some additional options you require, but for most cases the defaults are sufficient.

[root@bigboy milter-greylist-2.0.2]# ./configure && make && make install
checking for gcc… gcc
checking for C compiler default output file name… a.out
checking whether the C compiler works… yes

/usr/bin/install -c -d -m 755 /etc/mail
test -f /etc/mail/greylist.conf -o -f /etc/mail/greylist.except || \
/usr/bin/install -c -m 644 greylist.conf /etc/mail
/usr/bin/install -c -d -m 755 -o root /var/milter-greylist
[root@bigboy milter-greylist-2.0.2]#

The next step is to configure the package, which will be covered next.
Configuring milter-greylist

Configuring milter-greylist requires these four quick steps:

1. Add the milter-greylist statements listed in the README file to your /etc/mail/ file:

define(`confMILTER_MACROS_CONNECT’, `j, {if_addr}’)
define(`confMILTER_MACROS_HELO’, `{verify}, {cert_subject}’)
define(`confMILTER_MACROS_ENVFROM’, `i, {auth_authen}’)
define(`confMILTER_MACROS_ENVRCPT’, `{greylist}’)

2. There will be a number of shell scripts in the milter-greylist tar directory that correspond to various versions of Linux. Copy the correct version to your /etc/init.d directory and use the chkconfig command to make sure the milter starts on the next reboot.

[root@bigboy milter-greylist-2.0.2]# cp /etc/init.d/milter-greylist
[root@bigboy milter-greylist-2.0.2]# chmod 755 /etc/init.d/milter-greylist
[root@bigboy milter-greylist-2.0.2]# chkconfig –add milter-greylist
[root@bigboy milter-greylist-2.0.2]# chkconfig milter-greylist on
[root@bigboy milter-greylist-2.0.2]# chkconfig –list | grep milter
milter-greylist 0:off 1:off 2:on 3:on 4:on 5:on 6:off
[root@bigboy milter-greylist-2.0.2]#

3. Edit the /etc/mail/greylist.conf configuration file. Here we set the “try again later” to five minutes and use the whitelist command to deactivate the timer for trusted networks so that mail is delivered immediately.

# File: /etc/mail/greylist.conf

# How long a client has to wait before we accept
# the messages it retries to send. Here, 1 hour.
greylist 5m

# Whitelist addresses within my own home/office network
acl whitelist addr

4. Start the milter with the service command.

[root@bigboy milter-greylist-2.0.2]# service milter-greylist start
Starting Milter-Greylist: [ OK ]
[root@bigboy milter-greylist-2.0.2]#

Your new spam mitigation tool should now be fully functional. Delete the mister-greylist directory in /tmp and you should be ready to go!
Configuring milter-greylist

Now that we have milter-greylist installed, we need to be able to do some basic troubleshooting. The /var/log/maillog file should be used to determine what is happening to your mail. Here are two samples of what to expect:

Dec 24 00:32:31 bigboy sendmail[28847]: jBO8WVnG028847: Milter: to=,
reject=451 4.7.1 Greylisting in action, please come back in 00:05:00

Dec 23 20:40:21 bigboy milter-greylist: jBO4eF2m027418: addr from
rcpt : autowhitelisted for 24:00:00

In the first entry, the email received is given a tag (jBO8WVnG028847) based on key characteristics in the mail header and a request is sent to the sender to resend the email in five minutes. Any email that is received with the same calculated key within the autowhite period configured in the greylist.conf file will then be automatically accepted without delay. In the second entry, the email has been resent and immediately accepted. Any other email from that source within the next 24 hours will be accepted without delay.

Note: Greylisting is very effective, but you will have to tne its operation to make sure critical emails are not delayed at all. One soluton is to set the autowhite period in /etc/mail/greylist.conf to slightly more than 24 hours especially if you get mail from certain recipients, such as newsletters, on a daily basis. This makes them arrive without interruption.
A Simple PERL Script To Help Stop SPAM

Blacklists won’t stop everything, but you can limit the amount of unsolicited spam you receive by writing a small script to intercept your mail before it is written to your mailbox.

This is fairly simple to do, because sendmail always checks the .forward file in y

Veritas Cheat Sheet




vxdisk list
List all disks used by Veritas (VX).

vxdisk list
Display detailed information about a
single disk, including mutlipathing
information, size, type, Vx version,
and more.

Display report style information about
the current status of all Vx componants,
including disks, subdisks, plexes, and

Display report style information about
the current status of ONLY the componant
you request. So for instance,
"vxprint vol01" shows information about
all subcomponants of vol01. This works
for plexes, disk groups, etc.

vxprint -hrt
Display detailed information about all
Vx componanats, including stwdith,
ncolumns, offsets, layout type, read-
policy, and more. This is best for
a true picture of your configuration.

vxdg list
Display listing and state information
of all Disk Groups.

vxdg list
Display detailed information about
a diskgroup, including flags, version,
logs status, etc.

Display volume status and volume type.
By default, only displays "rootdg",
to display a diffrent Disk Group,
use "vxinfo -g ".

vxassist maxgrow
This command will output the maximum size
the volume specified can increased by,
specified in sectors.




Adds a disk to Vx by Initializing and Encapsolating
it. Specified by its device name (ex: c0t1d0s2).
NOTE: You’ll need to reboot to finalize the
disk addition!

This command, can also be used to add a disk to
a specified disk group. Just follow the prompts.
No reboots needed for changing DG’s.

vxedit rename
Rename a Vx disk. Ex: "vxedit rename disk01 disk05"

vxedit set reserve=on
Sets the "reserve" flag to a Vx disk. This
is used to keep specific disks from being
accidentally, or generally used.

vxdisk offline
Used to "offline" a disk. The disk should
be removed from its diskgroup before being

vxdisk rm
Used to remove disks from Vx control completely.
Ex: "vxdisk rm c0t1d0s2" Make sure to
removed the disk from its diskgroup, and offline
the disk before removing it.

vxedit set spare=on
Sets the "spare" flag to a Vx disk. This is used
to make the specified disk a hot spare, which
is then added to the "hot spare pool".

vxedit set spare=off
Same as above but removes the disk from the
"hot spare pool".




vxdg init =
Creates a new disk group, and assigns the naming
scheme to the first disk added to the group.
ex: "vxdg init newdg newdg01=c0t10d0s2".
NOTE: This is kinda tricky because the disk that
you’re adding can’t be a member of ANY DG, but
must be initialized. It’s easier to use
"vxdiskadd", and add the disk to a newdg by
specifying a new DG name for the DG field.

vxdg deport
Disabled a diskgroup, but doesn’t remove it. Often
used as an organized pool of disk to realocate, and
to moved DG’s from one system to another.

vxdg import
Reverse of above. Enables local access to the specified
disk group.

vxdg -n Change a Disk Groups name.

vxdg list
Use this to check the version numbers of Disk
Groups. Shows other details about the DG too.

vxdg destroy
Removes the specified DG, and frees all its disks
back to general use by Vx.

-= Quick Chart!: Disk Group Version Number Translation

VxVM Introduced Supported
Release Version Versions
——- ———— ———
1.2 10 10
1.3 15 15
2.0 20 20
2.2 30 30
2.3 40 40
2.5 50 50
3.0 60 20-60




vxmake sd ,,
Creates a subdisk with the specified name,
and by the offset and length specified.
ex: "vxmake sd disk02-01 disk02,0,8000"
NOTE: If you are going to add this subdisk
to a plex, its good to check the other
subdisks in that plex to see what their
lengths and offsets are, use the command:
"vxprint -st"

vxedit rm
Removes a subdisk.

vxsd assoc ,….
Associates the specified subdisks to
the specified plex. Example:
"vxsd assoc vol01-03 disk01-01,disk02-01"
NOTE: Striped volumes are diffrent,
you need to specify the column# so
use the following:

vxsd -l assoc ,…
Same as above, but used for associating
subdisks to a striped plex. Use the command
"vxprint -st" to see what other subdisk
in the plex look like, and then set the
new subdisks column number and offset
(found in the seventh column of output)
to the appropriate value.

vxsd aslog
Adds a log subdisk to the specified plex.
Ex: "vxsd aslog vol01-02 disk03-01"

vxsd dis
Disassociates the specified subdisk from its
current plex.




vxmake plex sd=,,….
Creates a new plex by the name specified and
assigns the specified subdisks to it.

vxmake plex layout= stwidth= ncolumn= sd=…
Like above command, but specifies layout type
as defined by , which is used for creation
of striped and RAID5 plexes. The layout is
constrained by the defined number of columns,
and stripe width. Subdisks specified are
added to the created plex.

vxplex att Associates specified plex with specified volume.
(Adds a mirror)
NOTE: Attachment will take a while. Watch
it with Vxtask, or via vxprint

vxplex dis Disassociate specified plex from its connected

vxedit -r rm Remove the plex.

vxmend off Offlines a plex for repair to it’s disks.

vxplex det Detaches specified plex from its connected
volume, but maintians association with it’s
volume. The plex is no longer used
for I/O untill it is (re)attached.

vxmend fix clean Used to clean plexes that are in the
"unclean" state. Used with unstartable

vxplex mv
Moves the data content from the origonal
plex onto a new plex.
NOTE: The old plex must be active (ENABLED).
The new plex should be the same length, or
larger than the old plex. The new plex
must not be associated with another volume.

vxplex cp
Copies the data from the specified volume
to a new plex.
NOTE: The new plex cannot be associated
with any other volume. The new plex,
further, will NOT be attached to
the specified volume. (Also, see notes
from above)




vxassist make
Creates a new volume with the name specified
and is made to the length specified.
Ex: "vxassist make newvol 10m"
NOTE: This command will pull disk space
from the generally avalible Vx disk space.

vxassist make layout= ….
Like the above command, but with layout specified.
The most common layouts are: striped and raid5
ex: "vxassist make newvol 100m layout=raid5 disk01 disk02 disk03"
NOTE: See the vxassist(1M) man page for more information.

vxmake vol len= plex=,…
Creates a new volume of specified length (usually
in sectors), and attachs the specified plexes to that
volume. Useful for creating volumes to house
copied or moved plexes.
NOTE: See the vxmake(1M) man page for more information.

vxvol init [plexname]
Manually sets the state of a volume.
NOTE: Not for the squimish.

vxassist maxsize [layout=raid5]
Returns the maximum size avalible via Vx to create
a new volume. By adding "layout=raid5" to the command
the calulations take into account losse due
to raid5. Output is in sectors and Megs.

vxassist maxgrow
Returns the maximum ammount of Vx space that
can be added to the specified volume.

vxassist mirror
Creates a mirror for the specified volume.
NOTE: Think of this as "handsfree plex creation".
This is fast, but the disks you want used
may not be used… often best to do manually.

vxassist addlog
Adds a Dirty Region Log (DRL) for the specified volume.

vxassist remove log
Reverse of above.

vxvol start
Starts a volume

vxvol stop
Stops a volume. Alternately you can use command as
such: "vxvol stopall" in order to stop all volumes.

vxassit growto/growby/shrinkto/shrinkby
Resizes the volume specified. Use one of the
following: growto, growby, shrinkto, and shrinkby
in order to descide what specifies.
By default length is specified in sectors.
This does not resize the filesystem inside the volume.
NOTE: Don’t shrink volumes to be less that
its contained filesystem! (duh)

vxvol set len=
An alternate to above command. Sets the absolute
lenths of the specified volume to the length
specified, by default, in sectors. This
does not resize the filesystem inside the volume.

NOTE: There is also a resize(1M) command, used
for resizing both volume AND filesytem. See
the man page for that one.

vxedit rm
Removes the specified volume. (poof!)
NOTE: If the volume specified is in the ENABLED
state, you will need to use the command
"vxedit -f ". Also, using the "r"
with "f" will remove all plexes and subdisks
with the volume. If you didn’t guess, "r"
is Recursive, and "f" is Force.

crontab header

Many times admins forget the field order of the crontab file
and alway reference the man pages over-and-over.

Make your life easy. Just put the field definitions in your crontab file
and comment (#) the lines out so the crontab file ignores it.

# 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
3 2 * * 1-5 /another/command/to/run

Emacs Cheat Sheet

This is a short tutor intended to get you started using emacs. In it,
you will learn the basics on how to move around within the file, how
to delete and add to the file, how to format the file, and how to save
and read files.

Emacs is a powerful screen editor. All commands are effected by a
combination of keystrokes making use of either the CONTROL or the
META keys. The CONTROL key will be designated as C-, the META key as
M-. Usually, the META key is the ESCAPE key. For example, you can
quit this session at any time by typing C-x C-c. If you make a
mistake entering a command, C-g will clear the command buffer. The
command buffer is displayed at the bottom of the screen, under the
line which has the file information.

Moving Within the File

It is important that one be able to move about the file quickly and
easily. To scroll from screen to screen, one uses C-v to move forward
and M-v to move backward. M-< will move to the beginning of the buffer and M-> will move to the end. C-l will center the current line
in the screen.

On some terminals, the arrow keys and/or the mouse may work, but this
is not true for all terminals. To move the cursor to the right or
left one character at a time, use C-b or C-f, respectively. To move
up one line, use C-p. C-n will move you down one line. When you move
up and down in the file, the cursor will remain in the same column if
possible. Now try moving the cursor around.

You can move the cursor from word to word, sentence to sentence, and
paragraph to paragraph. M-b will move the cursor to the beginning of
the previous word and M-f will move it to the beginning of the next
word. M-a will move to the beginning of the sentence and M-e will
move to the end of the sentence. M-[ will move backward to the
paragraph beginning and M-] will move to the paragraph end. Finally,
C-a and C-e will move the cursor to the beginning or end of the
current line. Use these commands to position the cursor at various
points within the file.

In emacs, one can also move the cursor to particular strings. This
search capability comes in several flavors. We will concentrate on
the incremental search. Position this paragraph so that all of it can
be seen on the screen and place the cursor at the end of this
sentence. Make sure that the cursor is not near the bottom of the
screen. Type C-r (backward search). You will find the following
message on the command line – ‘I-search backward:’. Now start typing
the word "particular", keeping the following questions in mind. What
happens to the cursor when you type the first character? The cursor
moves to the word "place" at the beginning of the sentence the
cursor was originally on. When you type the next character, the
cursor moves backward to the first word containing the string "pa".
In an incremental search, the search remains active until you hit
ESCAPE (leaves the cursor where it is) or C-g, which returns the
cursor to its original position. Try leaving the search using both

Now place the cursor at the beginning of this paragraph. Do a
backward search for "particular" again. The cursor moves to the first
occurence of the string that it finds. To move to the next occurence
while you are still in search mode, do another C-r. (Hit C-g to
return here.) C-s can be used to do a forward incremental search.

Deleting and Adding Text

Now that you know how to get around in the file, you will probably
want to do some real editting. This section will focus on the
deletion and addition of text, plus some aspects of formatting.

To delete a single character, type C-d to kill the current character.
The DELETE key will kill the character before the cursor. (NOTE: The
DELETE key and the BACKSPACE key are different on many keyboards.)
M-d will delete from the cursor to the end of the current word. Going
backward, M-DELETE will delete from the beginning of the current word
to but not including the cursor.

To delete to the end of the line, hit C-k. To delete to the beginning
of the line is somewhat trickier, you need to hit M-0 C-k (that’s a
zero, not the letter O). To delete to the end of a sentence, hit M-k.
Use C-x DELETE to delete to the beginning of a sentence.

Below is a sample paragraph which contains some extra characters or
words. Practice deleting on the mistakes in the next paragraph.

Deleting in emacs does not have to be difficult. For example, this
sentence can be deleted by placing the cursor at the beginning and
typing M-k. Another thing you can do is kill the word repeated in
this sentence twice twice. This sentence containes words with exxtra
letterrs in themm.

One can also mark a region to be killed. To do this, place the cursor
at one end of the region and set the mark by typing C-@. Now position
the cursor at the other end of the region and hit C-w. If you find
that you deleted something that you really wanted to keep, C-y will
yank back the last thing killed.

Being able to delete text is important, but it is also nice to add
text. This can be done by placing the cursor where you want to insert
text and start typing. When you place text in the middle of a line,
you will notice that the line will spill over onto the next line. You
can format the paragraph containing the cursor by typing M-q.

Another tool that comes in handy when editting is the search and
replace option. To replace with at every
occurrence after the cursor, simply type M-x replace-string RETURN,
then type in the string to be replaced followed by a RETURN, and then
the new string followed by a RETURN. The cursor will remain at the
last occurrence of replacement. To move back to the original
location, type C-u C-SPACEBAR. If you want to replace only certain
occurrences of the old string, use the command M-x

Try search and replace in the following example. In this example, you
will search for the term "rust-capped" and replace all occurrences with the
term "chestnut-sided". After you are done, use the M-q command to
re-format the paragraph.

In the spring time, the great migration is underway. Birds of all
sizes and shapes head northward to their breeding grounds. We enjoy
the sparrows, especially the rust-capped sparrows. Of course, the
warblers add much color to the audible fest. The rust-capped warblers
seem to be most populous in our area.

Saving and Reading Files

Now that you know how to edit a file, you will want to be able to save
the file. There are several ways to do this. The easiest is to
simply exit emacs using C-x C-c. You will be prompted by emacs to let
it know whether you really want to save the file or not.

At times, especially when editting a long file, you may wish to save
the file without exitting. This can be done by typing C-x C-s. You
will be prompted before the file is saved. You will also be prompted
when you commence editting. Should you wish to save the buffer into
another file, use C-s C-w.

Emacs allows you to work on more than one buffer. To read in a file
while in emacs, hit C-x C-f and enter the file name. This will open a
new buffer and insert the file into that buffer. You can list all of
the buffers currently open by typing C-x C-b. This will split the
screen and display the buffer information on the bottom. To get rid
of the bottom window, type C-x 1. To select another buffer, you can
use the C-x b command. C-x k will kill the buffer.

Other Emacs Commands To Know

Emacs allows you to suspend the editting session and return to the
shell. You can do this by typing C-z. This actually puts emacs in
the background. To get it back into the foreground, type fg or

Emacs has an extensive help facility. To access it, type C-h. Follow
the directions given in the command buffer. C-h C-h will provide help
on using the help facility. While in help, you will be able to a list
of commands whose names contain a string, display a table of all key
bindings in effect, print the name of the command that a key runs,
etc. C-h i will run Info, a program for browsing documentation files.
Info includes the complete Emacs manual. There is also an extensive
tutorial for emacs in the help facility. Type C-h t to access the

When the help facility is invoked, it is brought into its own buffer.
You can see this by typing C-x C-b to display the buffers. To exit
help and get back to your original buffer, type C-x b and enter the
buffer name if it is different from the default name given.

Emacs has many other features that are not described here. You will
find many listed in the tutorial and many more in the manual. Below
is a synopsis of the commands as given in the GNU Emacs Manual.
Summary of Emacs Commands

Starting emacs:
start up only emacs
start up with a file emacs filename

Leaving emacs:
suspend Emacs C-z
exit Emacs permanently C-x C-c

read a file into Emacs C-x C-f
save a file back to disk C-x C-s
insert a file into this buffer C-x i
replace this file with another C-x C-v
write buffer to a specified file C-x C-w
run the directory editor C-x d

Getting help:
starting HELP C-h
get rid of HELP window C-x 1
scroll HELP window ESC C-v
apropos C-h a
show function a key runs C-h c
describe a function C-h f
get mode-specific information C-h m

Error Recovery:
abort partially typed command C-g
recover file lost by system crash M-x recover-file
undo an unwanted change C-x u or C-_
restore buffer to original M-x revert-buffer
redraw garbaged screen C-l

Incremental Search:
search forward C-s
search backward C-r
regular expression search C-M-s
exit incremental search ESC
undo effect of last character DEL
abort current search C-g

entity to move over backward forward
character C-b C-f
word M-b M-f
line C-p C-n
go to line beginning/end C-a C-e
sentence M-a M-e
paragraph M-[ M-]
page C-x [ C-x ]
sexp C-M-b C-M-f
function C-M-a C-M-e
go to buffer beginning/end M-< M->

scroll to next screen C-v
scroll to previous screen M-v
scroll left C-x < scroll right C-x >

Killing and Deleting:
entity to kill backward forward
character(delete, not kill) DEL C-d
word M-DEL M-d
line(to end of) M-O C-k C-k
sentence C-x DEL M-k
sexp M– C-M-k C-M-k

kill region C-w
kill to next occurrence of char M-z char
yank back last thing killed C-y
replace last yank with previous kill M-y

set mark here C-@ or C-SPC
exchange point and mark C-x C-x
set mark arg words away M-@
mark paragraph M-h
mark page C-x C-p
mark sexp C-M-@
mark function C-M-h
mark entire buffer C-x h

Query Replace:
interactively replace a string M-%
using regular expressions M-x query-replace-regexp

Valid responses in query-replace mode are

replace this one, go on to next SPC
replace this one, don’t move ,
skip to next without replacing DEL
replace all remaining matches !
back up to the previous match ^
exit query-replace ESC
enter recursive edit(C-M-c to exit) C-r

Multiple Windows:
delete all other windows C-x 1
delete this window C-x 0
split window in 2 vertically C-x 2
split window in 2 horizontally C-x 5
scroll other window C-M v
switch cursor to another window C-x o
shrink window shorter M-x shrink-window
grow window taller C-x ^
shrink window narrower C-x {
grow window wider C-x }
select a buffer in other window C-x 4 b
find file in other window C-x 4 f
compose mail in other window C-x 4 m
run Dired in other window C-x 4 d
find tag in other window C-x 4 .

indent current line TAB
indent region C-M-\
indent sexp C-M-q
indent region rigidly arg columns C-x TAB
insert newline after point C-o
move rest of line vertically down C-M-o
delete blank lines around point C-x C-o
delete all white space around point M-\
put exactly one space at point M-SPC
fill paragraph M-q
fill region M-g
set fill column C-x f
set prefix each line starts with C-x .

Case Change:
uppercase word M-u
lowercase word M-l
capitalize word M-c
uppercase region C-x C-u
lowercase region C-x C-l
capitalize region M-x capitalize-region

The Minibuffer:
The following keys are defined within the minibuffer.
complete as much as possible TAB
complete up to one word SPC
complete and execute RET
show possible completeions ?
abort command C-g
Type C-x ESC to edit and repeat the last command that
used the minibuffer. The following keys are then
previous minibuffer command M-p
next minibuffer command M-n

select another buffer C-x b
list all buffers C-x C-b
kill a buffer C-x k

transpose characters C-t
transpose words M-t
transpose lines C-x C-t
transpose sexps C-M-t

Spelling Check:
check current word M-$
check region M-x spell region
check buffer M-x spell buffer

find tag M-.
find next occurrence of tag C-u M-.
specify a new tags file M-x visit-tags-table
regexp search on all files in tags table M-x tags-search
query replace on all the files M-x tags-query-replace
continue last tags search or query-replace M-,

execute a shell command M-!
run a shell command on the region M-|
filter region through a shell command C-u M-|
start a shell in window *shell* M-x shell

scroll forward SPC
scroll reverse DEL
beginning of message . (dot)
next non-deleted message n
previous non-deleted message p
next message M-n
previous message M-p
delete message d
delete message and back up C-d
undelete message u
reply to message r
forward message to someone f
send mail m
get newly arrived mail g
quit Rmail q
output message to another Rmail file o
output message in Unix-mail style C-o
show summary of headers h

Regular Expressions:
The following have special meaning inside a regular expression.
any single character . (dot)
zero or more repeats *
one or more repeats +
zero or one repeat ?
any char in set [ … ]
any char not in set [^ … ]
beginning of line ^
end of line $
backslash \\
alternative ("or") \|
grouping \( … \)
nth group \n
beginning of buffer \`
end of buffer \’
word break \b
not beginning or end of word \B
beginning of word \< end of word \>
any word-syntax char \w
any non-word-syntax char \W
char with syntax c \sc
char with cyntax not c \Sc

copy region to register C-x x
insert register contents C-x g
save point in register C-x /
move point to saved location C-x j

Enter the Info documentation reader C-h i
Moving within a node:
scroll forward SPC
scroll backward DEL
beginning of node . (dot)

Moving between nodes:
next node n
previous node p
move up u
select menu item by name m
select nth menu item by number (1-5) n
follow cross reference (return with l) f
return to last node you saw l
return to directory node d
go to any node by name g

run Info tutorial h
list Info commands ?
quit Info q
search nodes for regexp s

Keyboard Macros:
start defining a keyboard macro C-x (
end keyboard macro definition C-x )
execute last-defined keyboard macro C-x e
append to last keyboard macro C-u C-x
name last keyboard macro M-xname-last-kbd-macro
insert lisp definition in buffer M-x insert-kbd-macro

Commands Dealing with Emacs Lisp:
eval sexp before point C-x C-e
eval current defun C-M-x
eval region M-x eval-region
eval entire buffer M-x eval-current-buffer
read and eval minibuffer M-ESC
re-execute last minibuffer command C-x ESC
read and eval Emacs Lisp file M-x load-file
load from standard system directory M-x load-library

PJV 4/20/1990

Easy Shell scripting


Shell scripting can be defined as a group of commands executed in sequence. Let’s start by describing the steps needed to write and execute a shell script:

Step 1: Open the file using an editor (e.g., "vi" or "pico".)


Step 2: All shell scripts should begin with "#!/bin/bash" or whatever other shell you prefer. This line is called the shebang, and although it looks like a comment, it’s not: it notifies the shell of the interpreter to be used for the script. The provided path must be an absolute one (you can’t just use "bash", for example), and the shebang must be located on the first line of the script without any preceding space.

Step 3: Write the code that you want to develop. Our first shell script will be the usual "Hello World" routine, which we’ll place in a file called ‘’.

echo "Hello World"

Step 4:The next step is to make the script executable by using the "chmod" command.

chmod 744


chmod +x

Step 5: Execute the script. This can be done by entering the name of the script on the command line, preceded by its path. If it’s in the current directory, this is very simple:

bash$ ./
Hello World

If you want to see the execution step-by-step – which is very useful for troubleshooting – then execute it with the ‘-x’ (‘expand arguments’) option:

sh -x
+ echo ‘Hello World’
Hello World

Category: Shell scripting
Shell scripting can be defined as a group of commands executed in sequence.

To see the contents of a script, you can use the ‘cat’ command or simply open the script in any text editor:

bash$ cat
echo Hello World

Comments in a Shell

In shell scripting, all lines beginning with # are comments.

# This is a comment line.
# This is another comment line.

You can also have comments that span multiple lines by using a colon and single quotes:

: ‘This is a comment line.

Again, this is a comment line.

My God, this is yet another comment line.’

Note: This will not work if there is a single quote mark within the quoted contents.

As you may or may not know, variables are the most significant part of any programming language, be it Perl, C, or shell scripting. In the shell, variables are classified as either system variables or user-defined variables.
System Variables

System variables are defined and kept in the environment of the parent shell (the shell from which your script is launched.) They are also called environment variables. These variable names consist of capital letters, and can be seen by executing the ‘set’ command. Examples of system variables are PWD, HOME, USER, etc. The values of these system variables can be displayed individually by "echo"ing the system variables. E.g., echo $HOME will display the value stored in the system variable HOME.

When setting a system variable, be sure to use the "export" command to make it available to the child shells (any shells that are spawned from the current one, including scripts):

bash$ SCRIPT_PATH=/home/blessen/shellscript
bash$ export SCRIPT_PATH

Modern shells also allow doing all this in one pass:

bash$ export SCRIPT_PATH=/home/blessen/shellscript

User-Defined Variables

These are the variables that are normally used in scripting – ones that you don’t want or need to make available to other programs. Their names cannot start with numbers, and are written using lower case letters and underscores by convention – e.g. ‘define_tempval’.

When we assign a value to a variable, we write the variable name followed by ‘=’ which is immediately followed by the value, e.g., define_tempval=blessen (note that there must not be any spaces around the equals sign.) Now, to use or display the value in define_tempval, we have to use the echo command and precede the variable name with a ‘$’ sign, i.e.:

bash$ echo $define_tempval

The following script sets a variable named "username" and displays its content when executed.


echo "The username is $username"

Commandline Arguments

These are variables that contain the arguments to a script when it is run. These variables are accessed using $1, $2, … $n, where $1 is the first command-line argument, $2 the second, etc. Arguments are delimited by spaces. $0 is the name of the script. The variable $# will display the number of command-line arguments supplied; this number is limited to 9 arguments in the older shells, and is practically unlimited in the modern ones.

Consider a script that will take two command-line arguments and display them. We’ll call it ‘’:


echo "The first variable is $1"
echo "The second variable is $2"

When I execute ‘’ with command-line arguments like "blessen" and "lijoe", the output looks like this:

bash$ ./ blessen lijoe
The first variable is blessen
The second variable is lijoe

Exit status variable

This variable tells us if the last command executed was successful or not. It is represented by $?. A value of 0 means that the command was successful. Any other number means that the command was unsuccessful (although a few programs such as ‘mail’ use a non-zero return to indicate status rather than failure.) Thus, it is very useful in scripting.

To test this, create a file named "test", by running touch test . Then, "display" the content of the file:

bash$ cat test

Then, check the value of $?.

bash$ echo $?

The value is zero because the command was successful. Now try running ‘cat’ on a file that isn’t there:

bash$ cat xyz1
bash$ echo $?

The value 1 shows that the above command was unsuccessful.
Scope of a Variable

I am sure most programmers have learned (and probably worked with) variables and the concept of scope (that is, a definition of where a variable has meaning.) In shell programming, we also use the scope of a variable for various programming tasks – although this is very rarely necessary, it can be a useful tool. In the shell, there are two types of scope: global and local. Local variables are defined by using a "local" tag preceding the variable name when it is defined; all other variables, except for those associated with function arguments, are global, and thus accessible from anywhere within the script. The script below demonstrates the differing scopes of a local variable and a global one:


local local_var=100
echo "local variable is $local_var"
echo "global variable is $global_var"

echo "======================"
echo "=======outside ========"
echo "local variable outside function is $local_var"
echo "global variable outside function is $global_var"

Running the above produces the following output:

local variable is 100
global variable is blessen
=======outside ========
local variable outside function is
global variable outside function is blessen

Note the absence of any value for the local variable outside the function.
Input and Output in Shell Scripting

For accepting input from the keyboard, we use read. This command will read values typed from the keyboard, and assign each to the variable specified for it.


For output, we use the echo command.

echo "statement to be displayed"

Arithmetic Operations in Shell Scripting

Like other scripting languages, shell scripting also allows us to use arithmetic operations such as addition, subtraction, multiplication, and division. To use these, one uses a function called expr; e.g., "expr a + b" means ‘add a and b’.


sum=`expr 12 + 20`

Similar syntax can be used for subtraction, division, and multiplication. There is another way to handle arithmetic operations; enclose the variables and the equation inside a square-bracket expression starting with a "$" sign. The syntax is

$[expression operation statement]


echo $[12 + 10]

[ Note that this syntax is not universal; e.g., it will fail in the Korn shell. The ‘$((…))’ syntax is more shell-agnostic; better yet, on the general principle of "let the shell do what it does best and leave the rest to the standard toolkit", use a calculator program such as ‘bc’ or ‘dc’ and command substitution. Also, note that shell arithmetic is integer-only, while the above two methods have no such problem. — Ben ]
Conditional Statements

Let’s have some fun with a conditional statement like "if condition". Most of the time, we shell programmers have situations where we have to compare two variables, and then execute certain statements depending on the truth or falsity of the condition. So, in such cases, we have to use an "if" statement. The syntax is show below:

if [ conditional statement ]
… Any commands/statements …

The script cited below will prompt for a username, and if the user name is "blessen", will display a message showing that I have successfully logged in. Otherwise it will display the message "wrong username".


echo "Enter your username:"
read username

if [ "$username" = "blessen" ]
echo ‘Success!!! You are now logged in.’
echo ‘Sorry, wrong username.’

Remember to always enclose the variable being tested in double quotes; not doing so will cause your script to fail due to incorrect syntax when the variable is empty. Also, the square brackets (which are an alias for the ‘test’ command) must have a space following the opening bracket and preceding the closing one.
Variable Comparison

In shell scripting we can perform variable comparison. If the values of variables to be compared are numerical, then you have to use these options:

-eq Equal to
-ne Not Equal to
-lt Less than
-le Less than or equal to
-gt Greater than
-ge Greater then or equal to

If they are strings, then you have to use these options:

= Equal to
!= Not Equal to
< First string sorts before second > First string sorts after second
The "for" Loop

The most commonly used loop is the "for" loop. In shell scripting, there are two types: one that is similar to C’s "for" loop, and an iterator (list processing) loop.

Syntax for the first type of "for" loop (again, this type is only available in modern shells):

for ((initialization; condition; increment/decrement))



for (( i=1; $i <= 10; i++ )) do echo $i done This will produce a list of numbers from 1 to 10. The syntax for the second, more widely-available, type of "for" loop is: for in do

This script will read the contents of ‘/etc/group’ and display each line, one at a time:


for i in `cat /etc/group`
count=`expr "$count" + 1`
echo "Line $count is being displayed"
echo $i

echo "End of file"

Another example of the "for" loop uses "seq" to generate a sequence:


for i in `seq 1 5`
echo $i

While Loop

The "while" loop is another useful loop used in all programming languages; it will continue to execute until the condition specified becomes false.

while [ condition ]

The following script assigns the value "1" to the variable num and adds one to the value of num each time it goes around the loop, as long as the value of num is less than 5.



while [$num -lt 5]; do num=$[$num + 1]; echo $num; done

Category: Programming
[Break] code into small chunks called functions, and call them by name in the main program. This approach helps in debugging, code re-usability, etc.
Select and Case Statement

Similar to the "switch/case" construct in C programming, the combination of "select" and "case" provides shell programmers with the same features. The "select" statement is not part of the "case" statement, but I’ve put the two of them together to illustrate how both can be used in programming.

Syntax of select:

select in do

Syntax of case:

case $ in) statements ;;) statements ;;
*) echo "Sorry, wrong option" ;;

The example below will explain the usage of select and case together, and display options involving a machine’s services needing to be restarted. When the user selects a particular option, the script starts the corresponding service.


echo "***********************"
select opt in apache named sendmail
case $opt in
apache) /etc/rc.d/init.d/httpd restart;;
named) /etc/rc.d/init.d/named restart;;
sendmail) /etc/rc.d/init.d/sendmail restart;;
*) echo "Nothing will be restarted"
echo "***********************"

# If this break is not here, then we won’t get a shell prompt.


[ Rather than using an explicit ‘break’ statement – which is not useful if you want to execute more than one of the presented options – it is much better to include ‘Quit’ as the last option in the select list, along with a matching case statement. — Ben ]

In the modern world where all programmers use the OOP model for programming, even we shell programmers aren’t far behind. We too can break our code into small chunks called functions, and call them by name in the main program. This approach helps in debugging, code re-usability, etc.

Syntax for "function" is:

{ # start of function
} # end of function

Functions are invoked by citing their names in the main program, optionally followed by arguments. For example:


sumcalc ()
sum=$[$1 + $2]

echo "Enter the first number:"
read num1
echo "Enter the second number:"
read num2

sumcalc $num1 $num2

echo "Output from function sumcalc: $sum"

Debugging Shell Scripts

Now and then, we need to debug our programs. To do so, we use the ‘-x’ and ‘-v’ options of the shell. The ‘-v’ option produces verbose output. The ‘-x’ option will expand each simple command, "for" command, "case" command, "select" command, or arithmetic "for" command, displaying the expanded value of PS4, followed by the command and its expanded arguments or associated word list. Try them in that order – they can be very helpful when you can’t figure out the location of a problem in your script.

Resizing partitions

Resizing of partitions requires full backup and restore of the data in those
partitions and in any adjacent partitions which will be affected by the

Partitions which do not have their starting or ending cylinder changed do
not have
to be backed-up. They will not be affected.

Example: To grow "root" (Part. 0) and take away space from "/data"
(Part. 4), these partitions, as well as the partitions between them
must be backed up and restored since the boundaries of each one will
be affected by the resizing. In this example we will not have to backup
Part. 1 (swap) or Part. 2 (backup). This is because swap is not a filesystem
(only stores temporary info while the system is running) and "backup" is just
an unused slice spanning the entire drive (again, there is no filesystem on
Actually, part. 2 will not be touched at all.

Current layout of the disk:
Part Tag Flag Cylinders Size Blocks
0 root wm 0 – 808 600.43MB (809/0/0) 1229680
1 swap wu 809 – 1213 300.59MB (405/0/0) 615600
2 backup wm 0 – 2732 1.98GB (2733/0/0) 4154160
3 alternates wm 1214 – 1779 420.08MB (566/0/0) 860320
4 alternates wm 1780 – 1914 100.20MB (135/0/0) 205200
5 unassigned wm 1915 – 2184 200.39MB (270/0/0) 410400
6 usr wm 2185 – 2589 300.59MB (405/0/0) 615600
7 home wm 2590 – 2732 106.13MB (143/0/0) 217360

In the above example Part. (slice) 4 is mounted on /data (even though the
Tag shows "alternates". This is because there is no format tag for "data".
The tag field does not have to correspond to mountpoint name.)

So we have to backup Part 0, 3 and 4 only.

After the procedure:

Part Tag Flag Cylinders Size Blocks
0 root wm 0 – 878 652.38MB (879/0/0) 1336080
1 swap wu 879 – 1283 300.59MB (405/0/0) 615600
2 backup wm 0 – 2732 1.98GB (2733/0/0) 4154160
3 alternates wm 1284 – 1849 420.08MB (566/0/0) 860320
4 alternates wm 1850 – 1914 48.24MB (65/0/0) 98800
5 unassigned wm 1915 – 2184 200.39MB (270/0/0) 410400
6 usr wm 2185 – 2589 300.59MB (405/0/0) 615600
7 home wm 2590 – 2732 106.13MB (143/0/0) 217360

Here are the examples of commands used to perform this procedure:

1) Boot system into single user mode.
Note: If modifying partitions on the boot disk the system must be booted
from the CD-ROM.
This is because partition table cannot be modified on a disk with
mounted filesystems.
Also to get a reliable backup of the OS slices (/, /usr and /var) they
must be unmounted
while being backed up.

ok boot cdrom -s

2) Run fsck on each filesystem being backed up.

# fsck /dev/rdsk/c#t#d#s#
(c#t#d#s# is the address of the slice we are currently working on Ex.

3) Run ufsdump on each filesystem (assuming there is a tape drive /dev/rmt/0).
We are using a fresh tape foreach filesystem (for simplicity).

# ufsdump 0uf /dev/rmt/0 /dev/rdsk/c#t#d#s#

4) Start the format utility and layout the filesystems with new sizes and
label the disk.

5) Create the new file system(s) for each of the resized partitions.

# newfs /dev/rdsk/c#t#d#s#

6) Run fsck on the new file system(s).

# fsck /dev/rdsk/c#t#d#s#

7) Mount each new file system on a generic mount point and
cd to that mount point and restore each filesystem.

Insert that the tape containing the filesystem being restored.
# mount /dev/dsk/c#t#d#s# /mnt
# cd /mnt
# ufsrestore -rvf /dev/rmt/0
# rm restoresymtable
# cd /
# umount /mnt
(repeat above steps for each filesystem)

8) If resizing the / partition, reinstall the boot block.

# cd /usr/platform/`uname -i`/lib/fs/ufs
# installboot bootblk /dev/rdsk/c#t#d#s#
(c#t#d#s# is the address of the root slice)

9) Reboot

# reboot

qmail howto

1. Get the tarballs

Begin by unpacking your tarballs to an appropriate place (such as /usr/local/src/)
(You’ll need to become root now.)

root:/usr/local/src# tar zxvf qmail-1.03.tar.gz

Then you need to change to the qmail-1.03 folder.

root:/usr/local/src# cd qmail-1.03


Once you are in the qmail folder you will want to start by reading the FAQ and INSTALL files.

root:/usr/local/src/qmail-1.03# more INSTALL
root:/usr/local/src/qmail-1.03# more INSTALL.alias
root:/usr/local/src/qmail-1.03# more INSTALL.mbox

After you return, apply the oversize DNS packet patch. This patch is necessary because some providers (such as AOL) have decided to ignore the RFC’s, and return UDP DNS responses that are greater than 512 bytes. qmail’s DNS resolver library is strictly RFC compliant, and does not accept non-RFC-compliant replies. This patch enables qmail to correctly process illegal DNS replies. Note that if your caching DNS server is running dnscache (part of djbdns), you do not need to apply this patch.

To apply the patch, do the following (in the qmail source dir)

root:/usr/local/src/qmail-1.03# patch -p1 < /path/to/qmail-103.patch 3. Create the qmail home directory. The first thing we need to do on our road to qmail is to create the qmail home directory. This is the directory that almost all of qmail will reside in, including the configuration files, the queue, and the actual qmail binaries. # mkdir /var/qmail 4. Create the necessary users and groups to run qmail. Next, we need to create all of the users and groups that the various qmail daemons run as. See INSTALL.ids for these groups. The following commands should work on most Linux distributions, and Solaris: # groupadd nofiles # useradd -g nofiles -d /var/qmail/alias -s /bin/false alias # useradd -g nofiles -d /var/qmail -s /bin/false qmaild # useradd -g nofiles -d /var/qmail -s /bin/false qmaill # useradd -g nofiles -d /var/qmail -s /bin/false qmailp # groupadd qmail # useradd -g qmail -d /var/qmail -s /bin/false qmailq # useradd -g qmail -d /var/qmail -s /bin/false qmailr # useradd -g qmail -d /var/qmail -s /bin/false qmails Note: To obtain instructions for creating the qmail users on other operating systems, or if you are having problems with the commands above, read INSTALL.ids. *** NOTE: IF YOU DO NOT CREATE THESE USERS AND GROUPS, QMAIL WILL NOT WORK. *** 5. Compile qmail and related programs. The next step is to compile the programs and make the qmail directory tree. Type: root:/usr/local/src/qmail-1.03# make setup check qmail will then begin compiling. If you get a successful compile, then there will be a new directory tree under /var/qmail containing the complete qmail system. Compiling the rest of the required programs is trivial on most systems. An example for rblsmtpd: root:/# mkdir /package root:/# cd /package root:/package# tar zxvf /path/to/daemontools-0.76.tar.gz root:/package# cd admin/daemontools root:/package/admin/daemontools# package/install (on BSD systems, reboot now to start daemontools). For ucspi-tcp, fastforward and dot-forward, the compile is done exactly the same as the qmail-1.03 compile. Untar the tarball, cd into the source directory and type "make setup check". If everything compiles and installs correctly, you are done compiling. 6. Configure qmail. After qmail compiles, we will want to configure it. The easiest way to do this is: root:/usr/local/src/qmail-1.03# ./config The config script tries to do a reverse DNS lookup on all local IP addresses. If this doesn't work, then you've got some dirty work to do. Read INSTALL.ctl. As long as all of your local IP's are in your DNS, then you shouldn't have any problems. Otherwise you can do the following: root:/usr/local/src/qmail-1.03# ./config-fast This will create the necessary files in order to run qmail. After running config or config-fast, you will probably need to update some of the files in /var/qmail/control in order to make your qmail system usable. See Section 14: Control Files for a description of some of the commonly used control files and what they do. Warning: If the config scripts fail for some reason, do not attempt to continue this installation! If you start your qmail system without configuring it, it will not work properly, and you will also be running an open relay! 7. Install the qmail aliases. root:/usr/local/src/qmail-1.03# cd ~alias root:/var/qmail/alias# echo adam > .qmail-root
root:/var/qmail/alias# echo bob > .qmail-postmaster
root:/var/qmail/alias# echo bob > .qmail-mailer-daemon

Qmail uses files for every alias. This is one of the major ways that qmail differs from sendmail. This is explained in greater detail below. Note that there is an alias for root. This is because root does not receive mail in qmail. In fact, qmail-lspawn will immediately die and bounce the message if UID == 0. Read INSTALL.alias for more instructions.
8. Set up daemontools and create control directories.

Now that you’ve installed qmail, you’ll need to set everything up so that qmail starts when your system comes up. This is taken care of by the daemontools package, which, if you’ve followed the HOWTO carefully so far, should already be installed in /package/admin/daemontools.

First, we’ll need to create the qmail service and log directories.

# mkdir -p /var/qmail/supervise/qmail-send/log
# mkdir -p /var/qmail/supervise/qmail-smtpd/log
# chmod +t /var/qmail/supervise/qmail-send
# chmod +t /var/qmail/supervise/qmail-smtpd
# mkdir -p /var/log/qmail/qmail-send
# mkdir -p /var/log/qmail/qmail-smtpd
# chown -R qmaill /var/log/qmail

Now, it’s time to create some stuff in /var/qmail/supervise. First, cd to /var/qmail/supervise/qmail-send.

Here, we need to create a script called run with the following contents:

exec /var/qmail/rc

Now, we need to create /var/qmail/supervise/qmail-send/log/run with the following contents:

exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t s2500000 /var/log/qmail/qmail-send

Now, we will create similar files in /var/qmail/supervise/qmail-smtpd. For run, use the following:

QMAILDUID=`id -u qmaild`
NOFILESGID=`id -g qmaild`
exec /usr/local/bin/softlimit -m 2000000 \
/usr/local/bin/tcpserver -H -R -v -p -x /etc/tcp.smtp.cdb \
-u $QMAILDUID -g $NOFILESGID 0 smtp /var/qmail/bin/qmail-smtpd 2>&1

For log/run:

exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t s2500000 /var/log/qmail/qmail-smtpd

8a. Access Control

Before we can start up our qmail smtpd, we need to do some access control. The simplest way to do this is by using files in /etc. I use /etc/tcp.smtp as my access control file. If you don’t need to do any access control, /etc/tcp.smtp can have just one line:


Note that a default configuration does not allow for ANY relaying, even from localhost. To allow relaying from localhost and your local network, you would have to use something like this:,RELAYCLIENT=""

For more examples, man tcprules.

After you’ve created your rules, you need to activate them. tcpserver works by reading a cdb (database) file. You use the tcprules program to build the database file from your /etc/tcp.smtp file. This is accomplished by the following command:

# tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp 9. Kill sendmail!! If you've gotten this far, that means that you are ready to do away with rickety old sendmail for good. First, find the pid of your sendmail daemon and kill it!!! In Linux: # killall -TERM sendmail If you don't feel that you've gained enough pleasure from this experience, then restart sendmail and kill it again. After that, do the following: # mv /usr/lib/sendmail /usr/lib/sendmail.old # mv /usr/sbin/sendmail /usr/sbin/sendmail.old # ln -s /var/qmail/bin/sendmail /usr/lib/sendmail # ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail # mv /usr/sbin/newaliases /usr/sbin/newaliases.old # ln -s /var/qmail/bin/newaliases /usr/sbin/newaliases Note: /usr/sbin may not exist on your system. *** IMPORTANT: Killing the sendmail process is not the only step to removing sendmail. You will also need to remove the package from your system, or at the very least keep sendmail from starting when the system is started. You will need to consult the documentation for your particular operating system in order to do this. 10. Create /var/qmail/rc. /var/qmail/rc is one of the most important qmail files. It is responsible for starting qmail, but more importantly, it tells qmail what to do with every email it receives. rc contains the default delivery instructions for qmail. We want our system to support .forward files, and deliver mail to /var/spool/mail. Therefore, we need a /var/qmail/rc file that looks something like this: #!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start '|dot-forward .forward |preline procmail' There are other sample rc files in the /var/qmail/boot directory. It is generally not advisable to change your rc file unless you know what you're doing. 10a. Maildir. Maildir is an alternate way of delivering messages. Maildirs have the following benefits: * Lock-free -- This means Maildirs are reliable over NFS. * Enables use of qmail-pop3d, a secure POP3 daemon which comes with qmail. * Programs don't have to stat() /var/spool/mail every time they open your mailbox. On systems with a large userbase, this can make things excruciatingly slow. * Supported natively by the mutt MUA. There are also some disadvantages to using Maildirs. * Some popular mail programs, such as PINE, need to be patched and recompiled in order to use Maildirs. You will need the Bloodhounds International c-client Maildir patch in order to patch Pine. * Maildirs store each message in its own separate file. This consumes more inodes than keeping mail in one spool file. If you want to deliver to Maildirs in users' home directories instead of /var/spool/mail, you can change /var/qmail/rc to look something like this: #!/bin/sh exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start '|dot-forward .forward ./Maildir/' Remember, the Maildir must be owned by the user it belongs to. If you create maildirs as root, then you will have to use the chown command in order to change the ownership. You should include a Maildir in /etc/skel, so that the Maildir will be automatically created whenever you make a new user. To learn more about Maildirs, read INSTALL.maildir. 11. Starting qmail. Everything is in place now, and we are ready to start qmail. Since svscan is already running, all we need to do is create symlinks in /service to our control directories in /var/qmail/supervise. # ln -s /var/qmail/supervise/* /service/ qmail services should start within a few seconds. To check if the services have started, you can run ps. # ps auxww | grep qmail You should see several tasks running, at the very least qmail-send, and some supervise processes. If these processes don't show up within a minute, you've probably done something wrong, and you should go back and retrace your steps. Once the qmail processes show up, you can test local deliveries by following the instructions in TEST.deliver. You can check to make sure your qmail-smtpd is listening by telneting to port 25 of the local machine. 12. rblsmtpd. After MAPS, LLC went private, I have not been able to find an open relay database that I am comfortable using. Instead of blocking sites via rblsmtpd, I have instead set up TMDA, the Tagged Message Delivery Agent. It has far exceeded the effectiveness of any IP blackhole list I'v ever used. I very rarely get spam at all anymore, unless it is through one of my other accounts. My spam frequency has gone from approx. 20 spams a day to less than one a week. Since I'm not recommending the use of rblsmtpd anymore, I am not going to update this section further. The example provided should be enough to get you working with any of the current free open relay blacklists. I strongly advise against using rogue blacklists like SPEWS. rblsmtpd is a generic program that is part of ucspi-tcp and works with any SMTP server that can run under tcpserver (for example, qmail and sendmail.) If you only want to block sites that are listed in the MAPS RBL, then you do not need to give rblsmtpd any arguments except the name of the SMTP daemon to run. However, if you want to block based on other blocking systems, such as Relay Spam Stopper (RSS), you will need to run multiple instances of rblsmtpd, using the -b flag with the name of the server that you want each invocation to perform lookups at. In order to add rblsmtpd to your qmail installation, you must make some changes to the run script in /var/qmail/supervise/qmail-smtpd: #!/bin/sh QMAILDUID=`id -u qmaild` NOFILESGID=`id -g qmaild` exec /usr/local/bin/softlimit -m 2000000 \ /usr/local/bin/tcpserver -H -R -v -p -x /etc/tcp.smtp.cdb \ -u $QMAILDUID -g $NOFILESGID 0 smtp rblsmtpd /var/qmail/bin/qmail-smtpd 2>&1

If you have a good eye, you can see that we’ve added an rblsmtpd before the qmail-smtpd process. This will block mail which is listed in the zone. If we wanted to also use the RSS, we would add another rblsmtpd before qmail-smtpd, ie:

QMAILDUID=`id -u qmaild`
NOFILESGID=`id -g qmaild`
exec /usr/local/bin/softlimit -m 2000000 \
/usr/local/bin/tcpserver -H -R -v -p -x /etc/tcp.smtp.cdb \
-u $QMAILDUID -g $NOFILESGID 0 smtp rblsmtpd rblsmtpd /var/qmail/bin/qmail-smtpd 2>&1

You can add as many rblsmtpd processes as you want to check multiple blacklists.
13. RTFM

At this time, it would be a good idea to read some of the official documentation. Of course, you’re not going to do that, you’re going to continue reading my drivel. I have an almost obscene power over you now. It intoxicates me.

Anyway, back to qmail.
14. The control files.

Once you’ve got your qmail system set up and running, there are a few things you’re going to have to learn how to do. First of all, you’ll be happy to know, that virtual hosts are *WAY* easier to do in qmail than they are in sendmail.

Look in your /var/qmail/control directory. Most likely, it’ll look something like this:

nose:/var/qmail/control$ ls -la
total 8
drwxr-xr-x 2 root qmail 1024 Sep 29 10:08 .
drwxr-xr-x 10 root root 1024 Sep 18 02:48 ..
-rw-r–r– 1 root root 22 Sep 18 02:40 defaultdomain
-rw-r–r– 1 root root 27 Sep 18 02:40 locals
-rw-r–r– 1 root root 27 Sep 18 02:40 me
-rw-r–r– 1 root root 17 Sep 18 02:40 plusdomain
-rw-r–r– 1 root root 27 Sep 18 02:40 rcpthosts
-rw——- 1 root root 147 Sep 29 10:08 virtualdomains

The three most important files here (in order of importance) are:
me — (in fact qmail can survive with JUST this file. It contains your local host name. Including domain)
rcpthosts — (All of the hosts that qmail will receive mail for. All of your local domains must be in this file.)
Important: qmail bounces mail for domains not listed in rcpthosts. All of your domains, including virtual domains, must be listed in this file. In addition, not having an rcpthosts file turns your qmail server into an open relay. Running an open relay on the internet is not acceptable, and if you do, you will soon be listed by the various open-relay blacklists such as ORBS and RSS. locals — (All of the hosts that are local. I.E. mail sent to these hosts will be delivered to users in /etc/passwd.)
15. dot-qmail.

dot-qmail is an important concept and I think it deserves its own section, even though this document is a HOWTO. This is because you will use dot-qmail for 95% of what you will do with qmail once it’s installed.

dot-qmail is what tells qmail-local what to do with a message once it is received. With dot-qmail, a user can forward her mail, create ezmlm mailing lists (such as the qmail mailing list), create aliases under her own username, and call external programs such as autoresponders.

dot-qmail exists in the form of .qmail files in a user’s home directory. qmail-local reads these files in order to decide what to do with a message.

When qmail does not find a .qmail file, it follows the default delivery instructions in /var/qmail/rc (or whatever script you are running qmail-start from). Please see the man page for dot-qmail for a listing of the commands available.

The great thing about dot-qmail is that it lets users set up their own aliases. If my user account is named "adam", then I can set up a file called .qmail-info, which will contain commands for processing messages addressed to adam-info. dot-qmail can be used to create as many aliases as you’d like, and can even be used for distribution lists.
16. Virtual domains.

Thanks to dot-qmail, virtual domains are as easy as normal aliases to create. The file virtualdomains uses the following format:

Where user is the username of the user that receives mail for this domain. This seems complicated at first, but it is actually very intuitive.

If my user account adam is specified by virtualdomains to receive mail for, then any .qmail files I create in my home directory will work as aliases for, as well as their normal usage. So, .qmail-info becomes

But what if I want to manage more than one virtual domain from my user account?

The virtualdomains file makes this very intuitive as well. Instead of putting user as the recipient, just put user-ext as the recipient. For example:

With this configuration, creating virtual host aliases is just as easy, the only difference is that we add an extension to the dot-qmail filename. Now, becomes .qmail-example-info, and becomes .qmail-example2-info, etc.

If .qmail-ext doesn’t exist, qmail-local will try some default .qmail files. For example, if ext is foo-bar, qmail-local will try first .qmail-foo-bar, then .qmail-foo- default, and finally .qmail-default. If none of these exist, qmail-local will bounce the message. (Exception: for the basic user address, qmail-local treats a nonexistent .qmail the same as an empty .qmail.) This paragraph was taken directly from the dot-qmail man page.
17. Fastforward.

Most sendmail users will be familiar with /etc/aliases. djb’s fastforward package supports everything sendmail supports in /etc/aliases, plus more.

To activate /etc/aliases, put the following in /var/qmail/alias/.qmail-default:

| fastforward -d /etc/aliases.cdb

Congratulations, /etc/aliases is now active. You may add sendmail style aliases to /etc/aliases, along with virtual domain aliases (which sendmail doesn’t support). Be sure to run /var/qmail/bin/newaliases after making any changes to /etc/aliases. Read the file ALIASES in your fastforward source distribution for more detailed information.
18. The End.

qmail is an extremely fast, flexible, and secure MTA. There are many other applications for it, and I have not even begun to scratch the surface of what you can do with it. For more information, read the qmail web site