Contents:
Class Configuration Commands
Access Class in Rules
Class with m4
Pitfalls
Alphabetized Reference
A class is like an array of string values. In the LHS of rules it is sometimes advantageous to compare individual tokens to multiple strings when determining a match. The configuration class command provides this ability. The class command is similar to the macro definition command, except that instead of assigning a single value to a macro, it assigns many values to a class. Classes differs from macros in that they can be used only in the LHS of rules, whereas macros can be used in either the RHS or the LHS.
Two different configuration commands can be used to assign values to a class. The
C
configuration command is used to assign values from within the configuration file. The
F
configuration command is used in two ways: to assign values by reading them from a disk file or to assign values by running a program and reading the output. These commands may be intermixed to create a single class or used separately to create multiple classes.
You may wish to review the tutorial in Chapter 12, Class , to see a few typical applications of class.
The three forms for the class configuration command are the following:
CX list
values from configuration file FX file
values from a disk file FX
|program
values via another program
The class configuration command starts with either the letter
C
or
F
, which must begin a line. The
C
says values will be assigned as a part of the configuration command. The
F
says values will be assigned from an external file or program.
The
C
or
F
is immediately followed (with no intervening whitespace) by the name of the class (the
X
above). A class name is any single ASCII character or, beginning with V8.7
sendmail
a multicharacter name enclosed in curly braces:
CX list
all versions C{LongName} list
beginning with V8.7
See Section 31.4.2, "Multicharacter Names" for a full discussion of how to use multicharacter names.
Note that classes are separate from macros, so they may both use the same letter or name with no conflict.
The sendmail program reserves the lowercase letters for its own use as internally defined class names (although currently only a few are actually used). All uppercase letters and all names that begin with uppercase letters are available for use.
The
C
form of the class command causes values to be assigned from within the configuration file. In general, the class command looks like this:
CX list
values from configuration file C{XX} list
values from configuration file
Here, a
list
is a list of string elements (delimited by whitespace) that follows on the same line as the
C
command. Each word in
list
is appended to the array of values in the class
X
in the first case and to the class
{XX}
in the second. [1]
[1] Note that when a class name is a single character, it may be referenced with or without enclosing curly braces, with no change in meaning. That is,
CX
andC{X}
are equivalent.
Multiple declarations of the same named class may coexist in the configuration file. Each declaration after the first appends its string elements to the preceding list. That is,
CX string1 string2 CX string3 string4
produces the same class as does
CX string1 string2 string3 string4
Both create a class with four strings as elements.
When an array of values is built, whitespace is used to separate one value from another. Whitespace is defined by the C language
isspace
(3) routine and usually includes the space, tab, newline, carriage-return, and form-feed characters. Each line of text assigned to a class is broken up by
sendmail
into whitespace delimited words. When a line is indented with a space or a tab, that line is joined by
sendmail
to the preceding line. Thus the following three declarations also append four words to the class
X
:
CX string1 CX string2 CX string3 string4 tab
Words that are added to a class cannot be removed after sendmail has read them. Instead, they must be edited out of whatever file or program produced them, and the sendmail daemon must be killed and restarted.
The list of words in a class declaration can include macros. For example the following assigns the same values to class
X
as did the above example:
D{LIST} string1 string2 string3 string4 CX ${LIST}
Macros used in class declarations are expanded when the configuration file is read. Deferred macros (those with the
$&
prefix) may not be used in class declarations. But conditionals may:
CX ourhost$?{Domain}.${Domain}$.
The
F
form of the class configuration command allows values to be appended to a class from outside the configuration file. In general, the file command looks like either of the following:
FX file
values from a disk file FX
|program
values via another program (V8.7 and above, or IDA)
The
F
is immediately followed by the name of the class. This can be either a single-character name, as shown, or a multicharacter name. The name is followed by optional whitespace and then the name of a file or program. If the file or program begins with the pipe character (
|
), it is taken to be the name of a program to run. [2] Otherwise, it is taken to be the name of a file to read.
[2] This was removed from V8.1 sendmail because it presented a security risk. It was restored to V8.7 because sendmail now checks permissions more carefully and exec (2)'s the program itself instead of using the old, buggy popen (3) approach of yore.
If SCANF was defined when
sendmail
was compiled (see
Section 18.8.39, SCANF
), each line that is read from a file or program is parsed by the C language
scanf
(3) library routine. The formatting pattern given to
scanf
(3) is
%s
, which tells
scanf
(3) to read only the first whitespace-delimited word from each line of text. The file is opened for reading or the program is executed when the configuration file is processed. If either cannot be opened (for reading or execution),
sendmail
syslog
(3)'s the following error and ignores that configuration command:
cannot open what :why
file cannot exec what :why
program
Here, the
what
is the exact text that was given in the configuration file, and
why
is the text of a system error.
For the file form only, if the file may optionally not exist, you can prefix its name with a
-o
switch:
FX -o file
okay for file to not exist
This tells
sendmail
to remain silent if the file does not exit. The
-o
switch is useful when a configuration file is shared by several machines, only some of which need the external class macro file.
The
C
and
F
forms of the configuration command may be intermixed for any given class name. For example, consider a file named
/etc/local/names
with the following contents:
string3 string4
The following two configuration commands add the same four strings to the class
X
as did the
C
command alone in the previous section:
CX string1 string2 FX /etc/local/names
This creates a class with four strings as array elements. Whitespace delimits one string from the others in the
C
line declaration, and they are stored in the order in which they are listed. The file
/etc/local/names
is then opened and read, and each of the two words in that file is appended to the two words that are already in the class.
The file form of the class configuration command allows different formatting patterns to be used with
scanf
(3). [3] But the program form does not allow any variation, and so its
scanf
(3) pattern is always
%s
, which tells
scanf
(3) to read only the first whitespace-delimited word from each line of text:
[3] The version of sendmail that you are using must have been compiled with SCANF defined (see Section 18.8.39 ) for scanf (3) to be usable from within the configuration file.
FX file pat
with scanf(3) pattern FX
|program
always ``%s''
If the optional
pat
argument to the file form is missing, the pattern given to
scanf
(3) is
%s
. The
pat
argument is separated from the
file
argument by one or more spaces or tabs. It should not be quoted, and it consists of everything from its first character to the end of the line. Internally,
scanf
(3) is called with:
sscanf(result, pat, input)
Here,
result
is the string array element to be added to the class definition. The
pat
is the
scanf
(3) pattern, and
input
is the line of text read from the file. [4]
[4] Avoid using a bare
%s
as the pattern. Doing so risks overflowing internal sendmail buffers. Instead specify a limited string length with something like%.40s
.
After each line of text is read from the file and filtered with the scanf (3) pattern, it is further subdivided by sendmail into individual words. That subdividing uses whitespace (as defined by the C language isspace (3) routine) to separate words. Each separate word is then appended as an individual element to the class array.
Consider the contents of the following file named /etc/local/myhosts :
server1 server2 # my two nets uuhost # my uucp alias #mailhost # mail server alias (retired 06,23,91)
This file contains three hostname aliases to be added to a class, say
H
. The following configuration command does just that:
FH /etc/local/myhosts %[^\#]
The pattern
%[^#]
causes
scanf
(3) to read all characters in each line up to, but not including, the first
#
character. The first line includes two white-space delimited words that are appended to the class
H
. The second line contains one word, and the third contains none. The
\
character prevents
sendmail
from treating the
#
as a comment character.