\input texinfo @c -*-texinfo-*-exec
@c *********************************************************************
@c
@c  This is a TEXINFO file. It generates both TEX documentation and
@c  the "on line" documentation "info" files.
@c
@c  The file is structured like a programming language. Each chapter
@c  starts with a chapter comment.
@c
@c  Menus list the subsections so that an online info-reader can parse
@c  the file hierarchically.
@c
@c ***********************************************************************
@c %** start of header
@setfilename cfengine-Reference.info
@settitle Cfengine v2 reference
@setchapternewpage odd
@c %** end of header
@defindex mb

@include version1.texi

@titlepage
@title cfengine v2 reference
@subtitle Edition @value{EDITION} for version @value{VERSION}
@author Mark Burgess
@author Faculty of Engineering, Oslo University College, Norway

@c @smallbook

@page
@vskip 0pt plus 1filll
Copyright @copyright{} 2008 Mark Burgess

This manual corresponds to CFENGINE
Edition @value{EDITION} for version @value{VERSION}
as last updated @value{UPDATED}.

@end titlepage


@c *************************** File begins here ************************


@ifinfo
@dircategory System Utilities
@direntry
* cfengine Reference: (cfengine-Reference.info).
                        Cfengine is a language based tool specifically
                        designed for configuring and maintaining BSD
                        and System-5-like operating systems attached
                        to a TCP/IP network.
@end direntry
@end ifinfo

@ifnottex
@node Top, Reference introduction, (dir), (dir)
@top Cfengine-Reference
@end ifnottex


@ifinfo
Copyright @copyright{} 2008 Mark Burgess

This manual corresponds to CFENGINE
Edition @value{EDITION} for version @value{VERSION}
as last updated @value{UPDATED}.

@end ifinfo

@ifhtml
@html
<a href="#Contents"><h1>COMPLETE TABLE OF CONTENTS</h1></a>

<p>
This manual is for version @value{VERSION} of cfengine and
was last updated on the  @value{UPDATED}.
</p>

<h2>Summary of contents</h2>
@end html
@end ifhtml

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@menu
* Reference introduction::      
* Cfkey::                       
* Cfshow::                      
* Cfagent reference::           
* Cfservd.conf and cfrun reference::  
* Cfexecd reference::           
* Problem solving::             
* Example configuration file::  
* Variable Index::              
* Concept Index::               
* FAQ Index::                   
@end menu

@node Reference introduction, Cfkey, Top, Top
@chapter Introduction to reference manual

The purpose of the cfengine reference manual is to collect together and
document the raw facts about the different components of cfengine. Once
you have become proficient in the use of cfengine, you will no longer
have need of the tutorial. The reference manual, on the other hand,
changes with each version of cfengine. You will be able to use it
online, or in printed form to find out the details you require to
implement configurations in practice.


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@menu
* Installation::                
* Work directory::              
* Hard classes::                
* Filenames and paths::         
* Debugging with signals::      
@end menu

@node Installation, Work directory, Reference introduction, Reference introduction
@section Installation

@c chew begin Dependencies

In order to install cfengine, you should first ensure that the following
packages are installed.

@table @r
@item @b{OpenSSL}
Open source Secure Sockets Layer for encryption.@*URL: @url{http://www.openssl.org}
@item @b{BerkeleyDB} (version 3.2 or later)
Light-weight flat-file database system.@*URL: @url{http://www.oracle.com/technology/products/berkeley-db/index.html}
@end table

@c chew end Dependencies

@noindent
The preferred method of installation is then

@smallexample
tar zxf cfengine-x.x.x.tar.gz
cd cfengine-x.x.x
./configure
make
make install
@end smallexample

@noindent
This results in binaries being installed in @file{/usr/local/sbin}.
Since this is not necessarily a local file system on all hosts, users
are encouraged to keep local copies of the binaries on each host, inside
the cfengine trusted work directory.

@node Work directory, Hard classes, Installation, Reference introduction
@section Work directory

In order to achieve the desired simplifications, it was decided to
reserve a private work area for the cfengine tool-set. 
@c chew begin Work directory
In cfengine 1.x, the administrator could choose the locations of
configuration files, locks, and logging data independently. In
cfengine 2.x, this diversity has been simplified to a single directory
which defaults to @file{/var/cfengine} (similar to @file{/var/cron}):

@w{}
@smallexample
/var/cfengine
/var/cfengine/bin
/var/cfengine/inputs
/var/cfengine/outputs
@end smallexample
@c chew end Work directory

The installation location
@file{/usr/local/sbin} is not necessarily a local file system, and cannot
therefore be trusted to a) be present, and b) be authentic on an
arbitrary system.

Similarly, a trusted cache of the input files must now be maintained
in the @file{inputs} subdirectory. When cfengine is invoked by the
scheduler, it reads only from this directory. It is up to the user to
keep this cache updated, on each host. This simplifies and
consolidates the cfengine resources in a single place. The environment
variable @code{CFINPUTS} still overrides this default location, as before,
but in its absence or when called from the scheduler, this becomes the
location of trusted files.  A special configuration file @file{update.conf} is
parsed and run before the main configuration is parsed, which is
used to ensure that the currently caches policy is up-to-date. This has private
classes and variables.
@cindex @file{update.conf}
If no value is set for @code{CFINPUTS}, then the default location
is the trusted cfengine directory
@file{/var/cfengine/inputs}.


The @file{outputs} directory is now a record of spooled run-reports. These
are mailed to the administrator, as previously, or can be copied
to another central location and viewed in an alternative browser..


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Hard classes, Filenames and paths, Work directory, Reference introduction
@section Cfengine hard classes


A single class can be one of several things:

@c chew start Hard classes

@itemize @bullet

@item The name of an operating system architecture e.g.  @code{ultrix}, @code{sun4}, etc.
This is referred to as a @emph{hard class}.

@item The unqualified name of a particular host. If your system returns a fully
qualified domain name for your host, cfagent truncates it at the first dot.

@item The name of a user-defined group of hosts.

@item A day of the week (in the form @code{Monday, Tuesday, Wednesday, ..}).

@item An hour of the day (in the form @code{Hr00, Hr01 ... Hr23}).

@item Minutes in the hour (in the form @code{Min00, Min17 ... Min45}).

@item A five minute interval in the hour (in the form @code{Min00_05, Min05_10 ... Min55_00})

@item A day of the month (in the form @code{Day1, Day2, ... Day31}).

@item A month (in the form @code{January, February, ... December}).

@item A year (in the form @code{Yr1997, Yr2004}).

@item An arbitrary user-defined string.

@item The IP address octets of any active interface (in the form @code{@w{ipv4_192_0_0_1}},
@code{@w{ipv4_192_0_0}}, @code{@w{ipv4_192_0}}, @code{@w{ipv4_192}}).

@item The name of all interfaces Cfengine can find, in the form @code{net_iface_eth0}.

@end itemize

@c chew end Hard classes

To see all of the classes define on a particular host, run

@smallexample
host# cfagent -p -v
@end smallexample
as a privileged user. Note that some of the classes are set only
if a trusted link can be established with cfenvd, i.e. if both
are running with privilege, and the @file{/var/cfengine/state/env_data}
file is secure. More information about classes can be found in connection with
@code{allclasses}.

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Filenames and paths, Debugging with signals, Hard classes, Reference introduction
@section Filenames and paths

@c chew start Unix filenames

Filenames in Unix-like operating systems use for their directory
separator the forward slash '/' character. All references to file
locations must be absolute pathnames in cfengine, i.e. they must begin
with a complete specification of which directory they are in. For
example:

@smallexample
/etc/passwd
/usr/local/masterfiles/distfile
@end smallexample
@noindent
The only place where it makes sense to refer to a file without a complete
directory specification is when searching through directories for different
kinds of file, e.g.

@smallexample
tidy:

  /home/user pattern=core age=0 recurse=inf

@end smallexample

@noindent 
Here, one can write @file{core} without a path, because one is looking for any
file of that name in a number of directories.
@c chew end Unix filenames

@c chew start Windows filenames
The Windows operating systems traditionally use a different filename
convention.  The following are all valid absolute file names under
Windows:

@smallexample
 c:\winnt
 c:/winnt
 /var/cfengine/inputs
 //@var{fileserver}/share2/dir
@end smallexample
The `drive' name ``C:'' in Windows refers to a partition or device. Unlike Unix,
Windows does not integrate these seamlessly into a single file-tree.
This is not a valid absolute filename:

@smallexample
\var\cfengine\inputs
@end smallexample
Paths beginning with a backslash are assumed to be win32 paths.  They
must begin with a drive letter or double-slash server name.
@c chew end Windows filenames

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Debugging with signals,  , Filenames and paths, Reference introduction
@section Debugging with signals

It is possible to turn debugging output on or off on a running cfagent.  This is
useful for troubleshooting the cause of hangups, or for getting debugging output
from a cfagent launched from cfexecd.

A running cfagent process that receives a SIGUSR1 will immediately begin to behave
as if it had been invoked with the '-d2' option.  A SIGUSR2 will cause a running
cfagent to run as if the '-d2' option had not been invoked. 

Note that this output is often quite verbose.

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@menu
* Cfagent reference::           
* Cfservd.conf and cfrun reference::  
* Cfexecd reference::           
* Problem solving::             
* Example configuration file::  
* Variable Index::              
* Concept Index::               
* FAQ Index::                   
@end menu

@node Cfkey, Cfshow, Reference introduction, Top
@chapter Cfkey reference

@c chew start Key generation

The very first thing you should do on every host is to establish a
public-private key pair. To do this, you need to run the program

@smallexample
everyhost# cfkey
@end smallexample
@noindent
on every host. This program needs to produce random numbers, and needs a
source of randomness. A good strategy is to install and run the
@file{cfenvd} program for a week or two in advance of deploying cfengine
2, since @file{cfenvd} collects random events, which are an excellent source
of entropy for random number generation.
@cindex Key entropy and cfenvd
@cindex cfenvd and key entropy

If you get the error message ``PRNG not seeded'', it means that insufficient
data were found in order to make a random key. In that case, run @file{cfenvd}
for a few days more and try again.
@cindex PRNG not seeded

@c chew end Key generation

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@menu
* Cfagent reference::           
* Cfservd.conf and cfrun reference::  
* Cfexecd reference::           
* Problem solving::             
* Example configuration file::  
* Variable Index::              
* Concept Index::               
* FAQ Index::                   
@end menu

@node Cfshow, Cfagent reference, Cfkey, Top
@chapter Cfshow reference

The @code{cfshow} command was introduced in cfengine 2.1.11 in order to
provide a simple way to show some of the data stored by cfagent for
operational purposes.

@smallexample
everyhost# cfshow -a
everyhost# cfshow -l
everyhost# cfshow -c
everyhost# cfshow -s
everyhost# cfshow -p
everyhost# cfshow -f cfagent.conf -r linux.*
@end smallexample
@noindent

The command line options are

@table @samp

@item -a @code{--active}
This prints a list of any currently active locks, i.e. tasks that cfengine believes
it is currently enagaged in.

@item -A @code{--audit}
This prints a history of cfengine's behaviour collected if the
Auditing variable is true, @xref{Auditing}. The audit data are best viewed
in html or parsed with xml, using the @code{--html} and @code{--xml} options.

@item -c @code{--checksum}
This lists all of the files and their current checksum values in the
current checksum database.

@item -C @code{--classes}
This lists all of the classes that have been used on the system over the past
year, with frequency probabilities to show their relative occurrance rates and
last observed times.

@item -H @code{--html}
Generate output in web browser-friendly html.


@item -l @code{--locks}
This prints a list of the locks and the last times an active lock was secured for each
cfengine acivity. This list is potentially very long.
@item -s @code{--last-seen}
This lists the IP addresses of all known peers and the times they were last engaged in
communication with the current host. The expected interval between communications is also
printed. See FriendStatus. The output format is in a form that can easily be parsed by
user scripts. e.g.

@smallexample
IP + 192.168.1.101 192.168.1.101  @ [Tue Jan 23 16:13] not seen for (6.42) hrs, Av 0.02 +/- 0.01 hrs
IP - 192.168.1.101 192.168.1.101  @ [Tue Jan 23 16:13] not seen for (6.42) hrs, Av 0.02 +/- 0.01 hrs
@end smallexample

Lines marked with a + represent successful attempts made by cfagent on
the current host to connect to another host. Lines with a - are
connections attempted (but not necessarily succeeded) into cfservd from another
host's cfagent or cfrun.

@item -r @code{--regex} @var{regex}
Search the cfengine policy file (e.g. @file{cfagent.conf}) for rules
that belong to classes matching the named regular expression.  Note
that the class "any" is not automatically matched and the search is
based on the class text from the file. The output is not related to
which classes are currently defined.
	

@item -s @code{--performance}
Shows the time in seconds required to complete copies and shell executions.

@smallexample
(0.00 mins @ Tue Feb 13 19:05) Av 0.00 +/- 0.00 for Copy(localhost:/usr/local/sbin/cfagent > /var/cfengine/bin/cfagent)
(0.00 mins @ Tue Feb 13 19:05) Av 0.00 +/- 0.00 for Copy(localhost:/usr/local/sbin/cfenvd > /var/cfengine/bin/cfenvd)
(0.02 mins @ Tue Feb 13 19:05) Av 0.02 +/- 0.00 for Copy(localhost:/usr/local/sbin/cfexecd > /var/cfengine/bin/cfexecd)
(0.00 mins @ Tue Feb 13 19:05) Av 0.00 +/- 0.00 for Copy(localhost:/usr/local/sbin/cfservd > /var/cfengine/bin/cfservd)
(6.41 mins @ Tue Feb 13 18:50) Av 0.00 +/- 0.00 for Exec(/usr/bin/updatedb --prunepaths=/media)
(0.00 mins @ Tue Feb 13 19:05) Av 0.00 +/- 0.00 for Exec(/usr/sbin/ntpdate 128.39.74.16 > /dev/null)
@end smallexample

@item -X @code{--xml}
Generate output in xml for parsing by scripts etc.

@end table

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@menu
* Cfagent reference::           
* Cfservd.conf and cfrun reference::  
* Cfexecd reference::           
* Problem solving::             
* Example configuration file::  
* Variable Index::              
* Concept Index::               
* FAQ Index::                   
@end menu

@node Cfagent reference, Cfservd.conf and cfrun reference, Cfshow, Top
@chapter Cfagent reference

@menu
* Cfagent intro::               
* The file cfagent.conf::       
* Cfagent Runtime Options::     
* Variable expansion and contexts::  
* Cfengine classes::            
* acl::                         
* alerts::                      
* binservers::                  
* broadcast::                   
* control::                     
* classes::                     
* copy::                        
* defaultroute::                
* disks::                       
* directories::                 
* disable::                     
* editfiles::                   
* Editfiles on Binary Files::   
* files::                       
* filters::                     
* groups::                      
* homeservers::                 
* ignore::                      
* import::                      
* interfaces::                  
* links::                       
* mailserver::                  
* methods::                     
* miscmounts::                  
* mountables::                  
* processes::                   
* packages::                    
* rename::                      
* required::                    
* resolve::                     
* scli::                        
* shellcommands::               
* strategies::                  
* tidy::                        
* unmount::                     
@end menu

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Cfagent intro, The file cfagent.conf, Cfagent reference, Cfagent reference
@section Cfagent intro

Cfagent is the workhorse of cfengine. It interprets and computes the necessary strategies
for implementing convergent maintenance. In order to carry out work efficiently,
the agent groups similar actions together. The order of these actions is goverened by
a list called the actionsequence.

In many cases, cfagent will be able to complete all its work in a single
pass of the actionsequence. However, in complex configurations, it is
hard to resolve all of the ordering dependencies automatically in a
single pass. Cfagent keeps track both of all actions that have been
performed and of those that might still need to be performed (given that
some actions depend on the later outcomes of others). If there is a
possibility that an action ordering dilemma might occur, it runs a
second pass of the actionsequence to more quickly resolve the dependency
(avoiding the wait for next scheduled run).  No actions are performed
twice however, since the agent checks off actions that have already been
performed to avoid unnecessary duplication.

@menu
* The file cfagent.conf::       
* Cfagent Runtime Options::     
@end menu

@node The file cfagent.conf, Cfagent Runtime Options, Cfagent intro, Cfagent reference
@section The file cfagent.conf

@cartouche

@w{}
@smallexample

 control:

   @var{classes}::

       domain = ( @var{DNS-domain-name} )

 classes:

   @var{Class/Group definitions}

 import:

   @var{Files to import}

 # other items

@end smallexample

@end cartouche

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------


@node Cfagent Runtime Options, Variable expansion and contexts, The file cfagent.conf, Cfagent reference
@section Cfagent runtime options


@noindent Note that GNU long options are available with the syntax
@code{--longoption}.  The long names are given in brackets.
 
@table @samp
 
@item -a 
(@code{--sysadm}) Print only the name of the system administrator then quit.


@item -A
(@code{--auto}) Can be used to signify an automatic run of cfengine, as opposed
to a manual run. The distinction is not predetermined. Use of this option
currently causes cfengine to ignore locks. This option is reserved for future
development.

@item -b
(@code{--force-net-copy}) Normally cfengine detects attempts to copy
from a server via the network that will loop back to the localhost.
It then avoids using the network to make the copy. This option forces
cfengine to copy using the network. @emph{Yes, someone thinks this is useful!}

@item -c 
(@code{--no-check-files}) Do not check file systems for ownership / permissions etc.

@item -C 
(@code{--no-check-mounts}) Check mount points for consistency.  If this
option is specified then directories which lie in the ``mount point''
area are checked to see whether there is anything mounted on them.
Normally this is @emph{off} since not all machines use mounted file
systems in the same way.  e.g.  HPUX does not generally operate with
partitions, but nevertheless one might wish to mimick a partition-like
environment there, but it would be irritating to be informed that
nothing was mounted on the mount point.

@item -d 
(@code{--debug}) Enable debugging output.  Normally you will want to
send this to a file using the shell script command or a pipe.
 -d1 shows only parsing output.  -d2 shows only
runtime action output.  -d0 shows both levels. Debugging ouput is
intended mainly for the author's convenience and is not a supported
feature. The details of this output may change at any time.

@item -D 
(@code{--define}) Define a compound class symbol of the form
@emph{alpha.beta.gamma}.

@item -e
(@code{--no-edits}) Suppress file editing.

@item -E
(@code{--enforce-links}) Globally force links to be created where plain
files or links already exist. Since this option
is a big hammer, you have to use it in interactive mode and
answer a yes/no query before cfengine will run like this.

@item -f 
(@code{--file}) Parse filename after this switch.  By default cfengine
looks for a file called @emph{cfengine.conf} in the current directory.
 
@item -h  
(@code{--help}) Help information.  Display version banner and options
summary.

@item -H
(@code{--no-hard-classes}). Prevents cfengine from generating any built-in
class name information. Can be used for emulation purposes.
@cindex Internal classes, switching off
@cindex Switching off built-in classes
 
@item -i 
(@code{--no-ifconfig}) Do not attempt to configure the local area
network interface.

@item -I
(@code{--inform}) Switches on the inform output level, whereby cfengine
reports everything it changes..
 
@item -k
(@code{--no-copy}) Do not copy/image any files.

@item -K
(@code{--no-lock}) Ignore locks when running.

@item -l  
(@code{--traverse-links}) Normally cfengine does not follow symbolic
links when recursively parsing directories.  This option will force it
to do so.
 

@item -L
(@code{--delete-stale-links}) Delete links which do not point to
existing files (except in user home directories, which are not touched).

@item -m 
(@code{--no-mount}) Do not attempt to mount file systems or edit the
filesystem table.

@item -M
(@code{--no-modules})
Ignore modules in actionsequence.

@item -n 
(@code{--recon},@code{--dry-run},@code{--just-print}) No action.  Only
print what has to be done without actually doing it.

@item -N 
(@code{--negate},@code{--undefine}) Cancel a set of classes,
or undefine (set value to @emph{false}) a compound class of the form
@emph{alpha.beta.gamma}.

@item -p 
(@code{--parse-only}) Parse file and then stop.  Used for checking the
syntax of a program.  You do not have to be superuser to use this
option.

@item -P
(@code{--no-processes}) Do not execute the processes action.

@item -q
(@code{--no-splay}) Switch off host splaying (sleeping).

@item -Q
(@code{--quert}) Query the values of the comma separated list of variable names.

@item -s 
(@code{--no-commands}) Do not execute scripts or shell commands.

@item -S 
(@code{--silent}) Silence run time warnings.

@item -t 
(@code{--no-tidy}) Do not tidy file systems.

@item -u
(@code{--use-env}) Causes cfengine to generate an environment variable
@samp{CFALLCLASSES} which can be read by child processes (scripts). This
variable contains a summary of all the currently defined classes at any
given time. This option causes some System V systems to generate a Bus
Error or segmentation fault. The same information is available from the
cfengine built-in variable @code{$(allclasses)} and can be passed as a
parameter to scripts.
@cindex Environment variable CFALLCLASSES
@cindex CFALLCLASSES in a file
@cindex @file{allclasses} file
@vindex CFALLCLASSES
When this variable grows too large for embedding one can also access a complete
list of current classes in @file{/var/cfengine/state/allclasses}.

@item -U
(@code{--underscore-classes}). When this option is set, cfengine adds
an underscore to the beginning of the hard system classes (like @code{_sun4}, @code{_linux}
etc. The longer compound classes are not underscored, since these are already
complex and would unlikely result in collisions.) This can be used to avoid naming conflicts if you are so
unjudicious as to name a host by the name of a hard class. Other classes
are not affected.

@item -v  
(@code{--verbose}) Verbose mode.  Prints detailed information about
actions and state.

@item -V 
(@code{--version}) Print only the version string and then quit.

@item -x
(@code{--no-preconf}) Do not execute the @file{cf.preconf} net
configuration file.

@item -X
(@code{--no-links}) Do not execute the @code{links} section of a
program.

@item -w 
(@code{--no-warn},@code{--quiet}) Do not print warning
messages.

@item -z
(@code{--schedule}) Print the exec schedule for the LAN (used by cfexecd).

@end table

In version 2.0.4, an abbreviation for actionsequence exclusions was
added:

@w{}
@smallexample
$ cfagent --avoid resolve,copy
$ cfagent --just tidy --just shellcommands
@end smallexample

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Variable expansion and contexts, Cfengine classes, Cfagent Runtime Options, Cfagent reference
@section Variable expansion and contexts

Variables in cfengine 2 are defined in contexts. Variables in a given context
refer to the different phases of execution of cfengine: global, update and main.
In the "current" context, variables have the form

@smallexample
$(variable) $@{variable@}
@end smallexample
and are expanded either on parsing or at execution. Variables that cannot be
expanded remain as dollar strings. Variables belonging to a context that is not
the current one may be referred to as

@smallexample
$(@var{context}.variable)  or  $@{@var{context}.variable@}
@end smallexample
Note carefully that cfengine requires parentheses or braces around variable
names. Unlike in the shell, they cannot be omitted.  There is no difference
between these forms as far as cfengine is concerned.  Some authors like to use
the @code{()} form for cfengine variables, to distinguish them with shell
variables in command strings. The @code{()} form does not work in function
arguments, except inside quoted strings.

Consider the example:

@smallexample
$(global.env_time)
@end smallexample
Some variables in cfengine are associative arrays (as made famous by Perl).
Such arrays are referred to by square brackets:

@smallexample

$(array[key])  $(array[$(key)])

@end smallexample
@noindent


@c -------------------------------------------------------------------------------
@c SUBSECTION
@c -------------------------------------------------------------------------------


@menu
* Setting variables with functions::  
* Special variables::           
* Iteration over lists::        
@end menu

@node Setting variables with functions, Special variables, Variable expansion and contexts, Variable expansion and contexts
@subsection Setting variables with functions

A number of special functions can be used to set variables in cfengine.
You can import values from the execution of a shell command
by prefixing a command with the word @code{exec}. This method is deprecated
as of cfengine version 2; use the @code{ExecResult} function instead.

@cindex Variables, setting to result of a shell command
@vindex @code{exec}

@smallexample

  control:

   # old method

   listing = ( "exec /bin/ls -l" )

   # new method

   listing = ( ExecResult(/bin/ls -l) )

@end smallexample

@noindent
This sets the variable `listing' to the output of the command in the
quotes.
@cindex Built-in functions
@cindex Functions, built-in
@cindex Random numbers

Some other built-in functions are

@table @code
@item A(@var{X},@var{Y})
Makes an associative array entry, associating @var{X} and @var{Y}. For instance:

@smallexample
control:

 assoc_array = ( A(B,"is for bird") A(C,"is for cat") )

@end smallexample
@noindent
results in:

@smallexample

OBJECT: main
   4569 : assoc_array[B]=is for bird
   4630 : assoc_array[C]=is for cat

@end smallexample
@cindex Associative arrays.
Another example:

@smallexample
control:

 binhost = ( A(linux,machine1) A(solaris,machine2) )

copy:

 # Contact machine 1 for linux
 # Contact machine 2 for solaris

 /etc/source dest=/etc/receve server=$(binhost[$(class)])

@end smallexample

@item ExecResult(@var{command})
Executes the named command without a shell-wrapper and inserts the output into the
variable. Note that, when this is used in cfengine built-in list
variables, any spaces are interpreted as list separators. In other
lists, normal rules for iteration apply.

@item ExecShellResult(@var{command})
Executes the named command with a shell-wrapper and inserts the output into the
variable. Note that, when this is used in cfengine built-in list
variables, any spaces are interpreted as list separators. In other
lists, normal rules for iteration apply.


@item RandomInt(@var{a},@var{b})
Generate a random integer between a and b.


@item ReadArray(@var{filename},@var{fileformat},@var{separator},@var{comment},@var{Max number of bytes})
Reads up to a maximum number of bytes from a properly formatted file
into a one-dimensional associated array. File formats are:
@table @code
@item autokey
If this format is specified, @code{ReadArray} tries to interpret the
file as a table of items separated with the separator character. Blank
lines and comments (to end of line) are ignored.  Items are keyed
numerically starting from 1 to the maximum number in the file.  The
newline @code{$(n)} is always considered to be a separator, no matter
what the current separator is.
@cindex Associative arrays.

@item textkey
If this format is specified, @code{ReadArray} tries to interpret the file as a list
of lines of the form:

@smallexample
  key,value
@end smallexample

@end table


@item ReadFile(@var{filename},@var{Max number of bytes})
Read a maximum number of bytes from a file.
@cindex ReadFile

@item ReadTable(@var{filename},@var{fileformat},@var{separator},@var{comment},@var{Max number of bytes})
Reads up to a maximum number of bytes from a properly formatted file into a two-dimensional associated array.
@table @code
@item autokey
If this format is specified, @code{ReadArray} tries to interpret the
file as a table of items separated with the separator character. Blank
lines and comments (to end of line) are ignored.  Items are keyed
numerically starting from 1 to the maximum number in the file.  Any
lines that do not contain the correct number of separators cause the
function to fail without making any assignment.
@cindex ReadTable
@cindex Read array from table

@item textkey
If this format is specified, @code{ReadArray} tries to interpret the file as a list
of lines of the form:

@smallexample
  key1,key2,value1
  key3,key4,value2
@end smallexample

This variable would then be references as $(table[key1][key2]).

@end table


@item ReadList(@var{filename},@var{fileformat},@var{comment},@var{Max number of bytes})
Reads up to a maximum number of bytes from a properly formatted file into a listvariable. File formats
are:
@table @code
@item lines
If this format is specified, @code{ReadList} tries to interpret the file as a list of
items on separate lines. The value returned is a list formatted by the @code{Split} character.
@cindex Associative arrays.
@end table

@w{}
@smallexample
 
hosts = ( ReadList(/var/cfengine/inputs/datafile,lines,#,1000) )

@end smallexample

@item ReadTCP(@var{host/IP},@var{portnumber},@var{send string},@var{Max number of bytes})
Reads up to a maximum number of bytes from a TCP service. Can be used
to test whether certain services are responding to queries. It is
recommended that this be used primarily to check services running on
localhost. Bear in mind that this clause, executed on 100 hosts will produce
the effect of a distributed denial of service attack, so the probe should be
restricted to a single representative tester-host. For example:

@smallexample

one_host_only::
 
 # USE WITH CAUTION !

 probewww = ( ReadTCP(localhost,80,'GET index.html',1000) )

@end smallexample
Or testing a network service:
@smallexample
control:

 checkhost::

 probesmtp = ( ReadTCP(localhost,25,"",1024) )
 probewww  = ( ReadTCP(project.iu.hio.no,80,"GET /viewcvs HTTP/1.0 $@{n@}$@{n@}",1024) )

classes:

  viewcvs_error = ( RegCmp(".*Python Traceback.*","$@{probewww@}") )

alerts:

  viewcvs_error::

     "Received viewcvs error from web server"
@end smallexample


@item SelectPartitionNeighbours(@var{filename},@var{comment},@var{Policy},@var{group size})

This function is for use in peer to peer monitoring applications. It
allows individual hosts to identify themselves as part of a group and
find their peers. The function returns a list variable, delimited by
the list separation character, for use with Split.
@cindex SelectPartitionGroup
@cindex Peer to peer methods

@w{}
@smallexample

 control:

   allpeers = ( SelectPartitionNeighbours(/var/cfengine/inputs/cfrun.hosts,#,random,4) )

 copy:

   /data/file dest=/p2prepository/file server=$(allpeers)

@end smallexample

@item SelectPartitionLeader(@var{filename},@var{comment},@var{Policy},@var{group size})

This function is for use in peer to peer monitoring applications. It
allows individual hosts to identify themselves as part of a group and
select a leader.  This function reads a text file of hostnames or IP
addresses, one host per line, with blank lines and comments and
partitions it into groups of a fixed size. It then returns picks a
leader for the the group and returns its name as the value of the
function.
@cindex SelectPartitionLeader
@cindex Peer to peer methods

@w{}
@smallexample

 control:

   leader = ( SelectPartitionLeader(/var/cfengine/inputs/cfrun.hosts,#,random,4) )

 copy:

   /data/file dest=/p2prepository/file server=$(leader)

@end smallexample

@end table
Note that functions should have no spaces between the function name and the
leading parenthesis, but should themselves be surrounded by white space.
@noindent
For example:

@smallexample

control:

 variable2 = ( RandomInt(0,23) )

 variable3 = ( ExecResult(/bin/ls -a /opt) )

 myexcerpt  = ( ReadFile("/etc/services",220) )

 listvar = ( ReadArray(/tmp/array,textkey,",","#",100) )

@end smallexample

In the latter case, the file could look like this:

@smallexample
host$ more /tmp/array
one,String to tbe read
two,Nothing string
three,Everything comes in threes
@end smallexample
@noindent
and results in the definition of (verify with @code{cfagent -p -d3}):

@smallexample
OBJECT: main
   960 : listvar[one]=String to tbe read
   259 : listvar[two]=Nothing string
   224 : listvar[three]=Everything comes in threes
@end smallexample
@cindex Array example
@cindex Read array from file
@cindex Array from file
@cindex ReadArray

@c -------------------------------------------------------------------------------
@c SUBSECTION
@c -------------------------------------------------------------------------------

@menu
* Special variables::           
* Iteration over lists::        
@end menu

@node Special variables, Iteration over lists, Setting variables with functions, Variable expansion and contexts
@subsection Special variables


Variables are referred to in either of two different ways, depending on
your taste.  You can use the forms @code{$(variable)} or
@code{$@{variable@}}.  The variable in braces or parentheses can be the
name of any user defined macro, environment variable or one of the
following special built-in variables.

@table @code

@item AllClasses
A long string in the form @samp{CFALLCLASSES=class1:class2...}.  This
variable is a summary of all the defined classes at any given time. It
is always kept up to date so that scripts can make use of cfengine's
class data.
@cindex CFALLCLASSES
@vindex CFALLCLASSES
@cindex Class data and scripts
@cindex Scripts, passing classes to

@item arch
The current detailed architecture string---an amalgamation of the
information from @emph{uname}. @emph{A constant}.
@vindex $(arch)

@item binserver
The default server for binary data. @emph{A constant}.
@vindex $(binserver) 

@item cfinputs_version
The version string of the current configuration, used for version control and auditing.
@cindex Auditing
@cindex Version control
@vindex cfinputs_version

@item ChecksumDatabase
If set to the name of a file, cfagent will use this to store checksums of important
files, and give `tripwire functionality', @xref{ChecksumDatabase in cfagent}. This option was deprecated in 2.1.22.

@item ChecksumUpdates
If set to `on', security information is automatically updated.

@item class
The currently defined system hard-class (e.g. @code{sun4}, @code{hpux}). @emph{A constant}.
@vindex $(class)

@item date
The current date string. Note that if you use this in a shell command it might
be interpreted as a list variable, since it contains the default separator
@samp{:}.
@vindex $(date)

@item domain
The currently defined domain.
@vindex $(domain)

@item EmailFrom
The email address from whom email from cfexecd should appear to originate.

@item EmailMaxLines
Most lines of output to email from a single cfexecd-induced run of
cfagent. If undefined, defaults to 100. If set to 0, no email is sent by
cfexecd. If set to @code{inf}, no maximum is enforced.
@vindex $@{EmailMaxLines@}

@item EmailTo
The E-mail address to whom mail should be sent (overrides @code{sysadm} variable).

@item faculty
The faculty or site as defined in control (see @code{site}).
@vindex $(faculty)

@item fqhost
The fully qualified hostname of the system.
@vindex $(fqhost)

@item host
The hostname of the machine running the program.
@vindex $(host)

@item ipaddress
The numerical form of the Internet address of the host currently running
cfengine found by a reverse lookup in DNS.
@vindex $(ipaddress)

@item ipv4[@var{interface}]
The IPv4 address of the named interface as determined from a probe of the
interfaces. This variable belongs in the global context and refers to
as in the following examples:

@smallexample

$@{global.ipv4[hme0]@}
$@{global.ipv4[eth0]@}

@end smallexample

@item MaxCfengines
The maximum number of cfengines which should be allowed to
run concurrently on the system. This can prevent excessive
load due to unintentional spamming in situations where several
cfengines are started independently. The default value is unlimited.
@vindex MaxCfengines

@item ostype
A short for of @code{$(arch)}.

@item OutputPrefix
This quoted string can be used to change the default `cfengine:$@{hostname@}'
prefix on output lines to something else. You might wish to shorten
the string, or have a different prefix for different hosts. The default is
equivalent to,

@smallexample
  OutputPrefix = ( "cfengine:$(host):")
@end smallexample
@vindex OutputPrefix

@item RepChar
The character value of the string used by the file repository in
constructing unique filenames from path names. This is the character which
replaces @samp{/}.
@vindex repchar

@item site
This variable is identical to @code{$(faculty)} and may be used interchangeably.
@vindex $(site) 

@item smtpserver
The name of the host to which mail output should be sent.

@item split
The character on which list variables are split.
@vindex split

@item sysadm
The name or mail address of the system administrator.
@vindex $(sysadm)

@item timezone
The current timezone as defined in @code{control}.
@vindex $(timezone)


@item UnderscoreClasses
If this is set to `on' cfengine uses hard classes which begin with
an underscore to avoid name collisions, @xref{Cfagent Runtime Options}.
@vindex underscoreclasses
@cindex underscoreclasses
@cindex Name collision
@cindex Hostname collision
@cindex Hard class name collision
@vindex underscoreclasses

@item version
The current cfengine version string as defined in the code.
@vindex $(version)

@item year
The current year.
@vindex $(year)
@end table

@noindent
These variables are kept special because they play a special role in
setting up a system configuration.
You are encouraged to use them to define fully
generalized rules in your programs.  Variables can be used to advantage
in defining filenames, directory names and in passing arguments to shell
commands.  The judicious use of variables can reduce many definitions to
a single one if you plan carefully.

@cartouche

@emph{NOTE: the above control variables are not case sensitive, unlike
user macros, so you should not define your own macros with these names.}


@end cartouche

The following variables are also reserved and may be used to produce
troublesome special characters in strings.
@table @code

@item cr
Expands to the carriage return character.
@vindex $(cr)

@item colon
Expands to the colon @samp{:} character.
@vindex $(colon)

@item dblquote
Expands to a double quote @code{"}
@vindex $(dblquote)

@item dollar
Expands to @samp{$}.
@vindex $(dollar)

@item lf
Expands to a line-feed character (Unix end of line).
@vindex $(lf)

@item n
Expands to a newline character.
@vindex $(n)


@item quote
Expands to a single quote @code{'}.
@vindex $(quote)


@item spc
Expands simply to a single space. This can be used to place spaces in
filenames etc.
@vindex $(spc)

@item tab
Expands to a single tab character.
@vindex $(tab)

@end table

@c -------------------------------------------------------------------------------
@c SUBSECTION
@c -------------------------------------------------------------------------------

@node Iteration over lists,  , Special variables, Variable expansion and contexts
@subsection Iteration over lists

Variables can be used as iterators in some situations. Iteration over lists
is currently rather limited in cfengine and is something to be improved on
in a future version. When a variable is used as an iterator, a character
is chosen to represent a list separator, as in the shell @samp{IFS} variable.
The default separator is the colon @samp{:} character:

@smallexample
control:

 listvar = ( one:two:three:four )

@end smallexample
The action that contains a variable to be interpreted as a list appears
as separate actions, one for each case:

@smallexample
shellcommand:

  "/bin/echo $(listvar)"
@end smallexample
is equivalent to

@smallexample
shellcommand:

  "/bin/echo one"
  "/bin/echo two"
  "/bin/echo three"
  "/bin/echo four"
@end smallexample
If multiple iterators are used, these are handled as nested loops:

@smallexample
cfengine::/bin/echo one 1:     one 1
cfengine::/bin/echo one 2:     one 2
cfengine::/bin/echo one 3:     one 3
cfengine::/bin/echo one 4:     one 4
cfengine::/bin/echo two 1:     two 1
cfengine::/bin/echo two 2:     two 2
cfengine::/bin/echo two 3:     two 3
cfengine::/bin/echo two 4:     two 4
cfengine::/bin/echo three:     three 1
cfengine::/bin/echo three:     three 2
cfengine::/bin/echo three:     three 3
cfengine::/bin/echo three:     three 4
cfengine::/bin/echo four :     four 1
cfengine::/bin/echo four :     four 2
cfengine::/bin/echo four :     four 3
cfengine::/bin/echo four :     four 4
@end smallexample
Where iterators are not allowed, the implied lists are treated as scalars:

@smallexample

alerts:

 amnexus::

  "do $(list1) $(list2)"
@end smallexample
e.g.

@smallexample

cfengine:: do one:two:three:four 1:2:3:4
@end smallexample

Iterative expansion is currently restricted to:
@itemize @bullet

@item
In the directory field of the admit/deny server access rules,

@item
In the `from' field of a copy action,
@item
In the server field of the copy action,

@item
In the directory field of the disable action,

@item
In the directory field of the files action,

@item
In the `to' field of a multiple link action,


@item
In the directory field of the required/disk action,

@item
In a resolve item.

@item
In the directory field of a tidy action,

@item 
In the arguments, replyto and server attributes of methods.

@item
Names in the ignore action.

@item
A shellcommands body.

@item
In admit/deny path and attributes of cfserver.

@end itemize
@cindex split
@cindex Iteration over lists
@mbindex Iterating over lists
@vindex split


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node Cfengine classes, acl, Variable expansion and contexts, Cfagent reference
@section Cfengine classes
@cindex classes


A @emph{cfengine action} looks like this:

@smallexample

@var{action-type}:

   @var{compound-class}::
     
       @var{declaration}
@end smallexample 

@noindent
A single class is an identifier that may consist of any alphanumeric
character or the underscore, just like identifiers in ordinary programming
languages. Classes that are derived from data like IP addresses or host names
convert any other characters (like @samp{.} or @samp{-}) into underscores.
A single class can be one of several things:

@itemize @bullet

@item The name of an operating system architecture e.g.  @code{ultrix}, @code{sun4}, etc.
This is referred to as a @emph{hard class}.

@item The unqualified name of a particular host. If your system returns a fully
qualified domain name for your host, cfagent truncates it at the first dot.

@item The name of a user-defined group of hosts.

@item A day of the week (in the form @code{Monday, Tuesday, Wednesday, ..}).

@item An hour of the day (in the form @code{Hr00, Hr01 ... Hr23}).

@item Minutes in the hour (in the form @code{Min00, Min17 ... Min45}).

@item A five minute interval in the hour (in the form @code{Min00_05, Min05_10 ... Min55_00})

@item A quart hour (in the form @code{Q1, Q2, Q3, Q4})

@item An abbreviated time with quarter hour specified (in the form @code{Hr00_Q1, Hr23_Q4} etc.)

@item A day of the month (in the form @code{Day1 ... Day31}).

@item A month (in the form @code{January, February, ... December}).

@item A year (in the form @code{Yr1997, Yr2004}).

@item An arbitrary user-defined string.

@item The IP address octets of any active interface (in the form @code{@w{ipv4_192_0_0_1}},
@code{@w{ipv4_192_0_0}}, @code{@w{ipv4_192_0}}, @code{@w{ipv4_192}}).

@end itemize

A compound class is a sequence of simple classes connected by dots or
`pipe' symbols (vertical bars).  For example:

@cindex Compound classes
@cindex Classes, compound

@w{}
@smallexample

myclass.sun4.Monday::

sun4|ultrix|osf::

@end smallexample 
@noindent
A compound class evaluates to `true' if all of the individual classes
are separately true, thus in the above example the actions which follow
@code{compound_class::} are only carried out if the host concerned is in
@code{myclass}, is of type @code{sun4} and the day is Monday!
In the second example, the host parsing the file must be either of
type @code{sun4} @emph{or} @code{ultrix} @emph{or} @code{osf}.
In other words, compound classes support two operators: AND and OR,
written @samp{.} and @samp{|} respectively. 
 From cfengine version 2.1.1,
I bit the bullet and added @samp{&} as a synonym for the AND operator.
Cfengine doesn't
care how many of these operators you use (since it skips over blank
class names), so you could write either

@smallexample

solaris|irix::

@end smallexample

@noindent
or

@smallexample

solaris||irix::

@end smallexample

@noindent
depending on your taste. On the other hand, the order in which cfengine
evaluates AND and OR operations @emph{does} matter, and the rule
is that AND takes priority over OR, so that @samp{.} binds classes
together tightly and all AND operations are evaluated before ORing
the final results together. This is the usual behaviour in programming
languages. You can use round parentheses in cfengine classes to
override these preferences. 

Cfengine allows you to define switch on and off dummy classes so that
you can use them to select certain subsets of action.  In particular,
note that by defining your own classes, using them to make compound
rules of this type, and then switching them on and off, you can also
switch on and off the corresponding actions in a controlled way.  The
command line options @code{-D} and @code{-N} can be used for this
purpose.  See also @code{addclasses} in the Reference manual.
@vindex -N option
@vindex -D option
@cindex Classes, defining and undefining

@cindex NOT operator
@cindex Logical NOT
@vindex !
@cindex !
A logical NOT operator has been added to allow you to exclude
certain specific hosts in a more flexible way. The logical NOT
operator is (as in C and C++) @samp{!}. For instance, the
following example would allow all hosts except for @code{myhost}:

@smallexample
   @var{action}:

    !myhost::

        @var{command}
@end smallexample

@noindent
and similarly, so allow all hosts in a user-defined group @code{mygroup},
@emph{except} for @code{myhost}, you would write

@w{}
@smallexample
   @var{action}:

    mygroup.!myhost::

        @var{command}
@end smallexample

@noindent
which reads `mygroup AND NOT myhost'. The NOT operator can also be
combined with OR. For instance

@smallexample

   @var{class1}|!@var{class2}
@end smallexample

@noindent
would select hosts which were either in class 1, or those
which were not in class 2.

Finally, there is a number of reserved classes.  The following are hard
classes for various operating system architectures.  They do not need to
be defined because each host knows what operating system it is running.
Thus the appropriate one of these will always be defined on each host.
Similarly the day of the week is clearly not open to definition, unless
you are running cfengine from outer space.  The reserved classes are:

@smallexample
ultrix, sun4, sun3, hpux, hpux10, aix, solaris, osf, irix4, irix, irix64
   sco, freebsd, netbsd, openbsd, bsd4_3, newsos, solarisx86, aos,
          nextstep, bsdos, linux, debian, cray, unix_sv, GnU, NT
@end smallexample 

@noindent
If these classes are not sufficient to distinguish the hosts on
your network, cfengine provides more specific classes which
contain the name and release of the operating system. To find out
what these look like for your systems you can run cfengine in
`parse-only-verbose' mode:

@smallexample

  cfagent -p -v

@end smallexample
@noindent
and these will be displayed. For example, Solaris 2.4 systems
generate the additional classes @code{sunos_5_4} and @code{sunos_sun4m},
@code{sunos_sun4m_5_4}.

Cfengine uses both the unqualified and fully host names as classes. Some
sites and operating systems use fully qualified names for their
hosts. i.e. @code{uname -n} returns to full domain qualified
hostname. This spoils the class matching algorithms for cfengine, so
cfengine automatically truncates names which contain a dot `.'  at the
first `.' it encounters. If your hostnames contain dots (which do not
refer to a domain name, then cfengine will be confused. The moral is:
don't have dots in your host names! @emph{NOTE: in order to ensure that
the fully qualified name of the host becomes a class you must define the
domain variable.} The dots in this string will be replaced by underscores.
@cindex Fully qualified names
@cindex Dots in hostnames
@cindex Host name gets truncated

In summary, the operator ordering in cfengine classes is as follows:
@cindex Operator ordering
@mbindex Brackets (parentheses) in classes.
@mbindex Parentheses in classes.

@table @samp

@item ()
Parentheses override everything.

@item !
The NOT operator binds tightest.

@item . &
The AND operator binds more tightly than OR.

@item |
OR is the weakest operator.

@end table

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@menu
* Setting classes with special functions::  
* AccessedBefore::              
* ChangedBefore::               
* ClassMatch::                  
* FileExists::                  
* GroupExists::                 
* HostRange::                   
* IsDefined::                   
* IsDir::                       
* IsLink::                      
* IsPlain::                     
* IsNewerThan::                 
* IPRange::                     
* PrepModule::                  
* Regcmp::                      
* ReturnsZero::                 
* ReturnsZeroShell::            
* Strcmp::                      
* UserExists::                  
* IsGreaterThan::               
* IsLessThan::                  
* Examples setting classes::    
@end menu

@node Setting classes with special functions, AccessedBefore, Cfengine classes, Cfengine classes
@subsection Setting classes with special functions

Cfengine provides a number of built-in functions for evaluating classes,
based on file tests. Using these built-in functions is quicker than
calling the shell @code{test} function. The time functions place their
arguments in chronological order.


@node AccessedBefore, ChangedBefore, Setting classes with special functions, Cfengine classes
@subsection AccessedBefore

@smallexample 
AccessedBefore(@var{f1},@var{f2})
@end smallexample 

True if file 1 was accessed more recently than file 2 (UNIX atime)

@node ChangedBefore, ClassMatch, AccessedBefore, Cfengine classes
@subsection ChangedBefore

@smallexample 
ChangedBefore(@var{f1},@var{f2})
@end smallexample 
True if file 1's attributes were changed in any way more recently than file 2's (UNIX ctime)

@node ClassMatch, FileExists, ChangedBefore, Cfengine classes
@subsection ClassMatch

@smallexample 
ClassMatch(@var{regexp})
@end smallexample 

True if the quoted regular expression matches one of the currently defined classes.
It is wise to place ClassMatch at the end of your parsing in order to capture
as many of the user-defined classes as possible.

@smallexample
classes:

   userdef = ( ClassMatch(.*linux.*) )
@end smallexample

@node FileExists, GroupExists, ClassMatch, Cfengine classes
@subsection FileExists

@smallexample 
FileExists(@var{file})
@end smallexample 
True if the named file object (file/directory or link) exists.

@node GroupExists, HostRange, FileExists, Cfengine classes
@subsection GroupExists

@smallexample 
GroupExists(@var{groupname}|@var{gid})
@end smallexample 
True if the groupname or group id is registered on the system.

@node HostRange, IsDefined, GroupExists, Cfengine classes
@subsection HostRange

@smallexample 
HostRange(@var{basename},@var{start-stop})
@end smallexample 
True if the current relative domain name begins with basename and ends with an integer
between start and stop.  Note well: matching is case insensitive (both hostname and basename are converted to all lower case for comparison.) 

@node IsDefined, IsDir, HostRange, Cfengine classes
@subsection IsDefined

@smallexample 
IsDefined(@var{variable-id})
@end smallexample 
True if the named variable is defined. Note well: use the variable name, not its contents (that is,
@code{IsDefined(var)}, and not @code{IsDefined($@{var@})})

@node IsDir, IsLink, IsDefined, Cfengine classes
@subsection IsDir

@smallexample 
IsDir(@var{f})
@end smallexample 
True if the file f is a directory

@node IsLink, IsPlain, IsDir, Cfengine classes
@subsection IsLink

@smallexample 
IsLink(@var{f})
@end smallexample 
True if the file f is a symbolic link

@node IsPlain, IsNewerThan, IsLink, Cfengine classes
@subsection IsPlain

@smallexample 
IsPlain(@var{f})
@end smallexample 
True if the file f is a plain file

@node IsNewerThan, IPRange, IsPlain, Cfengine classes
@subsection IsNewerThan

@smallexample 
IsNewerThan(@var{f1},@var{f2})
@end smallexample 
True if file 2 was modified more recently than file 1 (UNIX mtime)

@node IPRange, PrepModule, IsNewerThan, Cfengine classes
@subsection IPRange

@smallexample 
IPRange(@var{address-range})
@end smallexample 
True if the current host lies within the specified IP range

@node PrepModule, Regcmp, IPRange, Cfengine classes
@subsection PrepModule

@smallexample 
PrepModule(@var{module},@var{arg1 arg2...})
@end smallexample 
True if the named module exists and can be executed. The module is assumed to
follow the standard programming interface for modules (see Writing plugin modules in tutorial).
Unlike actionsequence modules, these modules are evaluated immediately on parsing.
Note that the module should be specified relative to the authorized module directory.
@cindex Module directory
@cindex PrepModule
@cindex Modules executed immediately

@node Regcmp, ReturnsZero, PrepModule, Cfengine classes
@subsection Regcmp

@smallexample 
Regcmp(@var{regexp},@var{string or list separated string})
@end smallexample 
True if the string matched the regular expression regexp.

@node ReturnsZero, ReturnsZeroShell, Regcmp, Cfengine classes
@subsection ReturnsZero

@smallexample 
ReturnsZero(@var{command})
@end smallexample 
True if the named shell command returns with exit code zero (success).
The command is executed without a shell wrapper.

@node ReturnsZeroShell, Strcmp, ReturnsZero, Cfengine classes
@subsection ReturnsZeroShell

@smallexample 
ReturnsZeroShell(@var{command})
@end smallexample 
True if the named shell command returns with exit code zero (success) when executed
in the environment of a shell wrapper.

@node Strcmp, UserExists, ReturnsZeroShell, Cfengine classes
@subsection Strcmp

@smallexample 
Strcmp(@var{s1},@var{s2})
@end smallexample 
True if the string s1 exactly matches s2

@node UserExists, IsGreaterThan, Strcmp, Cfengine classes
@subsection UserExists

@smallexample 
UserExists(@var{username}|@var{uid})
@end smallexample 
True if the username or user id is registered on the system (this does not imply that
the user can log in or has a home directory).


@cindex IsGreatThan
@cindex IsLessThan
@cindex >
@cindex <

@node IsGreaterThan, IsLessThan, UserExists, Cfengine classes
@subsection IsGreaterThan

@smallexample 
IsGreaterThan(@var{s1},@var{s2})
@end smallexample 
Returns true if the value of s1 is greater than the value of s2. Note
that, if the strings have numerical values, a numerical comparison is
performed, otherwise a string comparison is used.

@node IsLessThan, Examples setting classes, IsGreaterThan, Cfengine classes
@subsection IsLessThan

@smallexample 
IsLessThan(@var{s1},@var{s2})
@end smallexample 
Returns true if the value of s1 is less than the value of s2. Note
that, if the strings have numerical values, a numerical comparison is
performed, otherwise a string comparison is used.
@smallexample

	control:
	
  	 actionsequence = ( files )
	
	 a = ( 2.12 )
 	 b = ( 2.11 )	
	
	classes:

	lt = ( IsLessThan($@{a@},$@{b@}) )
   	gt = ( IsGreaterThan($@{a@},$@{b@}) )

	alerts:

	  lt:: "$(a) LESS THAN $(b)"
	  gt:: "$(a) GREATER THAN $(b)"
@end smallexample


@node Examples setting classes,  , IsLessThan, Cfengine classes
@subsection Examples setting classes

@noindent
For example:

@smallexample

classes:

 access_to_dir = ( ReturnsZero(/bin/cd /mydir) )
 compare       = ( ChangedBefore(/etc/passwd_master,/etc/passwd) )
 isplain       = ( IsPlain(/tmp/import) )
 inrange       = ( IPRange(128.39.89.10-15) )
 CIDR          = ( IPRange(128.39.89.10/24) )
 compute_nodes = ( HostRange(cpu-,01-32)
 gotinit       = ( PrepModule(startup2,"arg1 arg2") )

@end smallexample
@cindex Classes, built-in functions
@cindex Testing files
@cindex File types
@cindex Comparing file objects
@vindex ReturnsZero()
@vindex ChangedBefore()
@vindex IsPlain()
@vindex IsDir()
@vindex IsLink()
@vindex IsNewerThan()
@vindex AccessedBefore()



@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node acl, alerts, Cfengine classes, Cfagent reference
@section acl
@cindex Access control lists
@cindex ACLs

@cartouche

@w{}
@smallexample

   acl:

      @var{class}::

         @{ @var{acl-alias}

         @var{action}
         @}

@end smallexample 
@end cartouche

@noindent

Cfengine's @code{ACL} feature is a common interface for managing
filesystem access control lists (ACLs). An access control list is an
extended file permission. It allows you to open or close a file to a
named list of users (without having to create a group for those users);
similarly, it allows you to open or close a file for a list of groups.
Several operating systems have access control lists, but each typically
has a different syntax and different user interface to this facility,
making it very awkward to use.  This part of a cfengine configuration
simplifies the management of ACLs by providing a more convenient user
interface for controlling them and---as far as possible---a common
syntax.

An ACL may, by its very nature, contain a lot of information. Normally
you would set ACLs in a @code{files} command, @xref{files}, or a
@code{copy} command, @xref{copy}. It would be too cumbersome to repeat
all of the information in every command in your configuration, so
cfengine simplifies this by first associating an alias together with a
complex list of ACL information. This alias is then used to represent
the whole bundle of ACL entries in a @code{files} or @code{copy}
command.  The form of an ACL is similar to the form of an
@code{editfiles} command.  It is a bundle of information concerning a
file's permissions.

@smallexample

 @{ @var{acl-alias}

  method:@b{overwrite}@var{/append}
  fstype:@var{posix/solaris/dfs/afs/hpux/nt}

  @var{acl_type}:@var{user/group}:@var{permissions}
  @var{acl_type}:@var{user/group}:@var{permissions}
  ...
 @}

@end smallexample

@noindent
The name @var{acl-alias} can be any identifier containing alphanumeric
characters and underscores. This is what you will use to refer to the
ACL entries in practice. The method entry tells cfengine how to
interpret the entries: should a file's ACLs be overwritten or only
adjusted?  Since the filesystems from different developers all use
different models for ACLs, you must also tell cfengine what kind of
filesystem the file resides on. Currently only Solaris and DCE/DFS ACLs
are implemented.

NOTE: if you set both file permissions and ACLs the file permissions
override the ACLs.

@c .....................................................
@c SUBSECTION
@c .....................................................

@menu
* ACEs::                        
* Solaris ACLs::                
* DFS ACLs::                    
* NT ACLs::                     
* Windows ACL Example::         
* Posix ACL Example::           
@end menu

@node ACEs, Solaris ACLs, acl, acl
@subsection Access control entries

An access control list is build of any number of individual access
control entries (ACEs). The ACEs has the following general syntax:

@smallexample
    @var{acl_type}:@var{user/group}:@var{permissions}
@end smallexample

@noindent
The user or group is sometimes referred to as a @emph{key}.
@cindex ACL key

For an explanation of ACL types and their use, refer to your local
manual page.  However, note that for each type of filesystem, there are
certain entries which must exist in an ACL. If you are creating a new
ACL from scratch, you must specify these.  For example, in Solaris ACLs
you must have entries for @code{user}, @code{group} and @code{other}.
Under DFS you need what DFS calls a @code{user_obj}, @code{group_obj}
and an @code{other_obj}, and in some cases @code{mask_obj}. In cfengine
syntax these are called @code{user:*:}, @code{other:*:} and
@code{mask:*:}, as described below.  If you are appending to an existing
entry, you do not have to re-specify these unless you want to change
them.

Cfengine can overwrite (replace) or append to one or more ACL
entries.

@table @code

@item overwrite
@code{method:overwrite} is the default. This sets the ACL according to
the specified entries which follow.  The existing ACL will be
overwritten completely.

@item append
@code{method:append} adds or modifies one or more specified ACL entries.
If an entry already exists for the specified type and user/group, the
specified permission bits will be added to the old permissions. If there
is no ACL entry for the given type and user/group, a new entry will be
appended.

@end table
@noindent
If the new ACL exactly matches the existing ACL, the ACL is not
replaced.

The individual bits in an ACE may be either added subtracted or
set equal to a specified mask. The @samp{+} symbol means add,
the @samp{-} symbol subtract and @samp{=} means set equal to.
Here are some examples:

@smallexample

  @var{acltype}:@var{id/*}:@var{mask}

  user:mark:+rx,-w
  user:ds:=r
  user:jacobs:noaccess
  user:forgiven:default

  user:*:rw
  group:*:r
  other:*:r

@end smallexample

@noindent
The keyword @code{noaccess} means set all access bits to zero for that
user, i.e. remove all permissions. The keyword @code{default} means
remove the named user from the access crontrol list altogether, so that
the default permissions apply. A star/asterisk in the centre field
indicates that the user or group ID is implicitly specified as of the
owner of the file, or that no ID is applicable at all (as is the case for `other').

@node Solaris ACLs, DFS ACLs, ACEs, acl
@subsection Solaris ACLs

Under Solaris, the ACL type can be one of the following:

@smallexample
        user
        group
        mask
        other
        default_user
        default_group
        default_mask
        default_other
@end smallexample
@noindent
A user or group can be specified to the user, group, default_user and
default_group types.
Solaris ACL permissions are the normal UNIX permissions bits @samp{rwx},
where:

@smallexample
    @var{
        @b{r} - Grants read privileges.
        @b{w} - Grants write privileges.
        @b{x} - Grants execute privileges.}
@end smallexample
@noindent



@c .....................................................
@c SUBSECTION
@c .....................................................

@node DFS ACLs, NT ACLs, Solaris ACLs, acl
@subsection DFS ACLs

@cindex DCE key
@cindex Key, ACL


In DCE, the ACL type can be one of the following:

@smallexample
        other
        mask
        any
        unauthenticated
        user
        group
        foreign_other
        foreign_user
        foreign_group
@end smallexample
@noindent
The @code{user}, @code{group}, @code{foreign_user} and @code{foreign_group}
 types require that you specify a user or group. The DCE documentation
refers to types @code{user_obj}, @code{group_obj} and so on. In the
cfengine implementation, the ugly @samp{_obj} suffix has been dropped to
make these more in keeping with the POSIX names. @code{user_obj::}, is
equivalent to @code{user:*:} is cfengine. The star/asterisk implies that
the ACL applies to the owner of the file object.

DFS permissions are comprised of the bits
@samp{crwxid}, where:

@w{}
@smallexample
        @b{c} - Grants control privileges, to modify an acl.
        @b{r} - Grants read  privileges.
        @b{w} - Grants write privileges.
        @b{x} - Grants execute privileges.
        @b{i} - Grants insert privileges.
        @b{d} - Grants delete privileges.
@end smallexample
@noindent
See the DCE/DFS documentation for more information about this.

It is not possible to set ACLs in foreign cells currently using
cfengine, but you can still have all of your ACL definitions in the same
file. You must however arrange for the file to be executed on the server
for the cell concerned.  Note also that you must perform a DCE login
(normally as user @samp{cell_admin}) in order to set ACLs on files
which are not owned by the owner of the cfengine-process.  This is
because you must have a valid security ticket.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node NT ACLs, Windows ACL Example, DFS ACLs, acl
@subsection NT ACLs

@cindex NT, ACL

NT ACEs are written as follows:

@smallexample
       acl_type:user/group:permissions:accesstype
@end smallexample

The actual change consists of the extra field containing the access
type. A star/asterisk in the field for @var{user/group} would
normally imply that the ACL applies to the owner of the file
object. However this functionality is as of today not yet implemented.

In NT, the ACL type can be one of the following:

@smallexample
           user
           group
@end smallexample
Both types require that you specify the name of a user or a group. 

NT permissions are comprised of the bits @samp{rwxdpo}, where:

@smallexample
    r - Read privileges
    w - Write privileges
    x - Execute privileges
    d - Delete privileges
    p - Privileges to change the permissions on the file
    o - Privileges to take ownership of the file
@end smallexample
In addition to any combination of these bits, the word @code{noaccess}
or @code{default} can be used as explained in the previous section. NT
comes with some standard, predefined permissions. The standards are only
a predefined combination of the different bits specified above and are
provided with cfengine as well. You can use the standards by setting the
permission to @code{read}, @code{change} or @code{all}. The bit
implementation of each standard is as on NT:

@smallexample
           read   - rx
           change - rwxd
           all    - rwxdpo
@end smallexample
where the bits follow the earlier definition. The keywords mentioned
above can only be used alone, and not in combination with @samp{+},
@samp{-}, @samp{=} and/or other permission bits.

NT defines several different access types, of which only two are used in
connection with the ACL type that is implemented in cfengine for NT. The
access type can be one of the following:

@smallexample
           allowed
           denied
@end smallexample
Intuitively, @code{allowed} access grants the specified permissions to
the user, whilst @code{denied} denies the user the specified
permissions. If no access type is specified, the default is
@code{allowed}. This enables cfengine's behaviour as on UNIX systems
without any changes to the configuration file. If the permissions
@code{noaccess} or @code{default} is used, the access type will be
irrelevant.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Windows ACL Example, Posix ACL Example, NT ACLs, acl
@subsection Windows ACL Example

Here is an example of a configuration file for an NT ACL:

@smallexample
control:
        actionsequence = ( files )
        domain = ( iu.hioslo.no )

files:
        $(HOME)/tt    acl=acl_alias1    action=fixall

acl:
        @{ acl_alias1

        method:overwrite
        fstype:nt

        user:gustafb:rwx:allowed
        user:mark:all:allowed
        user:toreo:read:allowed
        user:torej:default:allowed
        user:ds2:+rwx:allowed

        group:dummy:all:denied
        group:iu:read:allowed
        group:root:all:allowed
        group:guest:dpo:denied
        @}
@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Posix ACL Example,  , Windows ACL Example, acl
@subsection Posix ACL Example

Here is an example of a configuration file for one Solaris ACL and one DCE/DFS ACL:

@smallexample
control:
        actionsequence = ( files )
        domain = ( iu.hioslo.no )

files:
        $(HOME)/tt    acl=acl_alias1    action=fixall
        /:/bigfile    acl=acl_alias2    action=fixall

acl:
        @{ acl_alias1

        method:overwrite
        fstype:posix

        user:*:rwx
        user:mark:=rwx
        user:sowille:=rx
        user:toreo:=rx
        user:torej:default
        user:ds2:+rwx
        group:*:rx
        group:iu:r
        group:root:x
        mask:*:rx
        other:*:rx

        default_user:*:=rw
        default_user:mark:+rwx
        default_user:ds:=rwx
        default_group::=r
        default_group:iu:+r
        default_mask::w
        default_other::rwx
        @}
 
        @{ acl_alias2

        method:overwrite
        fstype:dfs

        user:*:rwxcid
        group:*:rxd
        other:*:wxir
        mask:*:rxw
        user:/.../iu.hioslo.no/cell_admin:rc
        group:/.../iu.hioslo.no/acct-admin:rwxcid
        user:/.../iu.hioslo.no/root:rx
        @}
@end smallexample

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node alerts, binservers, acl, Cfagent reference
@section alerts
@cindex Alerts
@vindex alerts

Alerts are normally just messages that are printed when classes become activated
in order to alert the system administrator to some condition that has arisen.
Alerts can also be special functions, like @code{ShowState()} that generate
system output.

Alerts cannot belong to the class @code{any}, that would generate a message from
every host. In a huge network this could result in vast amounts of Email. This behaviour
can be forced, however, by creating an alias for the class `any' that is defined on
the affected hosts.

@smallexample

alerts:

   class::

      @var{quoted message} 

        ifelapsed=@var{time}
        audit=@var{true/false}

      ShowState(@var{parameter})
      SysLog(@var{priority},@var{message})
      SetState(@var{name},@var{ttl},@var{policy})
      UnSetState(@var{name})
      FriendStatus(@var{hours})
      PrintFile(@file{filename},@var{lines})

@end smallexample
For example:
@cindex ShowState()
@cindex SysLog()
@cindex SetState()
@cindex UnsetState()

@w{}
@smallexample

alerts:

  myclass::

  "Reminder: say hello every hour" ifelapsed=60

  nfsd_in_high_dev2::

  "High NFS server access rate 2dev at $(host) value $(value_nfsd_in) av $(average_nfsd_in) pm $(stddev_nfsd_in)"
  ShowState(incoming.nfs)

 # ROOT PROCS

  anomaly_hosts.RootProcs_high_dev2::

   "RootProc anomaly high 2 dev on $(host) value $(value_rootprocs) av $(average_rootprocs) pm $(stddev_rootprocs)"
  ShowState(rootprocs)

@end smallexample

The @code{ShowState()} function reports on state gathered by the cfenvd
daemon.

@smallexample
ShowState(incoming.tcpsyn)
ShowState(outgoing.smtp)
ShowState(incoming.www)
ShowState(outgoing.www)
ShowState(procs)
ShowState(rootprocs)
ShowState(otherprocs)
ShowState(users)
@end smallexample

To limit the frequency of alerts, you can set locking times:

@smallexample
 # ROOT PROCS

  anomaly_hosts.RootProcs_high_dev2::

   "RootProc anomaly high 2 dev on $(host) value $(value_rootprocs) av $(average_rootprocs) pm $(stddev_rootprocs)"

   ShowState(rootprocs)  ifelapsed=10 expireafter=20

@end smallexample
Alerts can also be channeled directly to syslog, to avoid extraneous console messages or email.

@smallexample

  SysLog(LOG_ERR,"Test syslog message")

@end smallexample
One application for alerts is to pass signals from one cfengine to
another by persistent, shared memory.  For example, suppose a short-lived anomaly event
triggers a class that relates to a security alert. The event class might be too short-lived
to be followed up by cfagent in full. One could thus set a long term class that would
trigger up several follow-up checks.
A persistent class could also be used to exclude an operation for an interval of time.

Persistent class memory can be
added through a system alert functions to give timer behaviour.
For example, consider setting 
a class that acts like a non-resettable timer. It is defined for exactly 10
minutes before expiring.

@smallexample

  SetState("preserved_class",10,Preserve)

@end smallexample
Or to set a class that acts as a resettable timer. It is defined for 60 minutes unless
the SetState call is called again to extend its lifetime.

@smallexample

  SetState(non_preserved_class,60,Reset)

@end smallexample
Existing persistent classes can be deleted with:

@smallexample

          UnsetState(myclass)

@end smallexample


The @code{FriendStatus} function is available from version 2.1.4 and
displays a message if hosts that normally have a cfengine protocol
connection with the current host have not connected for more than than
specified number of hours. If the number of hours is set to zero,
cfengine uses a machine-learned expectation value for the time and uses
this to report. The friend status of a host is thus the expectation that
there is a problem with a remote peer. Expected contact rates of more than
the variable @code{LastSeenExpireAfter} are ignored as spurious, @xref{lastseenexpireafter}.

@cindex FriendStatus
@cindex Last Seen database
@cindex Peer watching (FriendStatus)
@cindex Monitoring other hosts
@cindex PrintFile

The @code{PrintFile} function can be used to display short excerpts from text files.
The arguments are the filename and a maximum number of lines to be printed.


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node binservers, broadcast, alerts, Cfagent reference
@section binservers
@cindex Binary servers, defining
@cindex Defining a binary server
@vindex binservers

The @code{binservers} declaration need only be used if you are using
cfengine's model for mounting NFS filesystems.  This declaration informs
hosts of which other hosts on the network possess filesystems containing
software (binary files) which client hosts should mount.  This includes
resources like programs in @code{/usr/local} and so on.  A host may have
several binary servers, since there may be several machines to which
disks are physically attached.  In most cases, on a well organized
network, there will be only one @emph{architecture server} per UNIX
platform type, for instance a SunOS server, an ULTRIX server and so on.

Binary servers are defined as follows:

@smallexample

binservers:

   physics.sun4::   sunserver sunserver2
   physics.linux::  linuxserver 

@end smallexample 

@noindent
The meaning of this declaration is the following.  All hosts of type
@code{sun4} which are members of the group @code{physics} should mount
any binaries declared in the @code{mountables} resource list which
belong to hosts @code{sunserver} or @code{sunserver2}.  Similarly all
@code{linux} machines should mount binary filesystems in the mountables
list from @code{linuxserver}.

Cfengine knows the difference between binaries and home directories in
the @code{mountables} list, because home directories match the pattern
given by @code{homepattern}.  @xref{homepattern}.  @xref{homeservers}.

Note that every host is a binary server for itself, so that the first
binary server (and that with highest priority) is always the current
host.  This ensures that local filesystems are always used in preference
to NFS mounted filesystems.  This is only relevant in connection with
the variable @code{$(binserver)}.
@cindex Binary servers, priority

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node broadcast, control, binservers, Cfagent reference
@section broadcast

@cindex Broadcast address
@vindex broadcast

This information is used to configure the network interface for each host.

Every local area network has a convention for determining which internet
address is used for broadcast requests.  Normally this is an address of
the form @code{aaa.bbb.ccc.255} or @code{aaa.bbb.ccc.0}.  The difference
between these two forms is whether all of the bits in the last number
are ones or zeroes respectively.  You must find out which convention is
used at your establishment and tell cfengine using a declaration of the
form:

@smallexample
broadcast:

  any::

     ones     # or zeros, or zeroes

@end smallexample 
@vindex ones
@vindex zeroes
@vindex zeros
@cindex ones
@cindex zeros

@noindent
In most cases you can use the generic class @code{any}, since all of the
hosts on the same subnet have to use the same convention.  If your
configuration file encompasses several different subnets with different
conventions then you will need to use a more specific.

Cfengine computes the actual value of the broadcast address using the
value specified above and the netmask @xref{netmask}.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node control, classes, broadcast, Cfagent reference
@section control
@cindex control section
@vindex control

The fundamental piece of any cfengine script or configuration file is
the control section.  If you omit this part of a cfengine script, it
will not do anything! The control section is used to define certain
variables, set default values and define the order in which the various
actions you have defined will be carried out.  Because cfengine is a
declarative or descriptive language, the order in which actions appear
in the file does not necessarily reflect the order in which they are
executed. The syntax of declarations here is:

@cartouche

@w{}
@smallexample
  control:

     @var{classes}::

        @var{variable} = ( @var{list or value} @var{function}(@var{args}) )

@end smallexample
@end cartouche

The control section is a sequence of declarations which looks something
like the following example:

@smallexample

control:

  site     = ( univ )
  domain   = ( univ.edu )
  sysadm   = ( admin@@computing.univ.edu )
  netmask  = ( 255.255.252.0 )
  timezone = ( EDT )
  nfstype  = ( nfs )

  childlibpath = ( /usr/local:/mylibs )

  sensiblesize  = ( 1000 )
  sensiblecount = ( 2 )
  editfilesize  = ( 4000 )

  actionsequence =
     (
     links.some
     mountall
     links.others
     files
     )

  myvariable = ( something )
  mymacro    = ( somethingelse )
  myrandom   = ( RandomInt(3,6) )
  myexcerpt  = ( ReadFile("/etc/services",220))

@end smallexample 

@noindent
Parentheses are required when making a declaring information in cfengine.
Note that a limited number of built-in functions exists:
@cindex RandomInt() function
@cindex ReadFile() function
@itemize @bullet
@item 
@code{ExecResult}(@var{command}) Executes the named shell command and
inserts the output into the variable.  Note that, when this is used in
cfengine built-in list variables, any spaces are interpreted as list
separators. In other lists, normal rules for iteration apply.
@item 
@code{RandomInt(a,b)}
Is substituted for a random number between (a,b).
@item 
@code{ReadFile}(@var{filename},@var{Max number of bytes})
A maximum number of bytes is read from the named file and placed in a variable.
@end itemize
For more functions, @xref{Setting variables with functions}.

@vindex site
@vindex domain
@vindex sysadm
@vindex netmask
@vindex timezone
@vindex nfstype
@vindex sensiblecount
@vindex sensiblesize
@vindex editfilesize
@vindex actionsequence
@vindex LD_LIBRARY_PATH
@vindex AbortClasses

The meaning of each of these lines is described below.

@menu
* AbortClasses::                
* access::                      
* actionsequence::              
* addclasses::                  
* addinstallable::              
* AllowRedefinitionOf::         
* Auditing::                    
* AutoDefine::                  
* BinaryPaddingChar::           
* BindToInterface in cfagent::  
* ChecksumDatabase in cfagent::  
* ChecksumPurge::               
* ChecksumUpdates::             
* CompressCommand::             
* childlibpath::                
* copylinks::                   
* defaultcopytype::             
* defaultpkgmgr::               
* deletenonuserfiles::          
* deletenonownerfiles::         
* deletenonusermail::           
* deletenonownermail::          
* domain::                      
* dpkginstallcommand::          
* dryrun::                      
* editbinaryfilesize::          
* editfilesize::                
* emptyresolvconf::             
* exclamation::                 
* excludecopy::                 
* excludelinks::                
* ExpireAfter::                 
* FreeBSDInstallCommand::       
* FreeBSDRemoveCommand::        
* FullEncryption::              
* homepattern::                 
* HostnameKeys in cfagent::     
* IfElapsed in cfagent::        
* IgnoreFriendRegex::           
* IgnoreInterfaceRegex::        
* Inform::                      
* interfacename::               
* fileextension::               
* lastseen::                    
* lastseenexpireafter::         
* linkcopies::                  
* LogDirectory::                
* LogTidyHomeFiles::            
* moduledirectory::             
* mountpattern::                
* netmask::                     
* nonalphanumfiles::            
* nfstype::                     
* PortageInstallCommand::       
* repchar::                     
* repository::                  
* RPMcommand::                  
* rpminstallcommand::           
* schedule::                    
* secureinput::                 
* sensiblecount::               
* sensiblesize::                
* showactions::                 
* singlecopy::                  
* site::                        
* SkipIdentify::                
* Smtpserver::                  
* SplayTime::                   
* split::                       
* spooldirectories::            
* suninstallcommand::           
* suspiciousnames::             
* sysadm::                      
* Syslog::                      
* SyslogFacility::              
* timezone::                    
* TimeOut::                     
* Verbose::                     
* Warnings::                    
* warnnonuserfiles::            
* warnnonownerfiles::           
* warnnonusermail::             
* warnnonownermail::            
@end menu


@c .....................................................
@c SUBSECTION
@c .....................................................

@node AbortClasses, access, control, control
@subsection AbortClasses

The @code{AbortClasses} list is a list of class identifiers that will
result in the abortion of the current cfagent instanitation with an error message
containing the name of the offending class.

@smallexample

 AbortClasses = ( emergency nologin_exists )

@end smallexample
@cindex Aborting cfagent
@cindex AbortClasses
This mechanism allows one to make controlled exceptions at the agent level. For example

@smallexample
control:

 actionsequence = ( shellcommands )

 AbortClasses = ( danger_will_robinson )

shellcommands:

  "shellcom 1"
  "shellcom 2" define=ok elsedefine=danger_will_robinson

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node access, actionsequence, AbortClasses, control
@subsection access
@cindex Access control
@vindex Restricting access

The @code{access} list is a list of users who are to be allowed to
execute a cfengine program.  If the list does not exist then all users
are allowed to run a program.

@smallexample
   access = ( @var{user1} @var{user2} ...  )
@end smallexample

@noindent
The list may consist of either numerical user identifiers or valid
usernames from the password database.  For example:

@smallexample
   access = ( mark aurora 22 456 )
@end smallexample

@noindent
would restrict a script to users mark, aurora and user id
22 and 456.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node actionsequence, addclasses, access, control
@subsection actionsequence
@cindex action sequence
@vindex actionsequence

The action sequence determines the order in which collective actions are
carried out.  Here is an example containing the full list of
possibilities:

@smallexample
   actionsequence = 
      (
      mountall               # mount filesystems in fstab
      mountinfo              # scan mounted filesystems
      checktimezone          # check timezone
      netconfig              # check net interface config
      resolve                # check resolver setup
      unmount                # unmount any filesystems
      packages               # install/upgrade/remove packages
      shellcommands          # execute shell commands
      editfiles              # edit files
      addmounts              # add new filesystems to system
      directories            # make any directories
      links                  # check and maintain links (single and child)
      mailcheck              # check mailserver
      mountall               # (again)
      required               # check required filesystems
      tidy                   # tidy files
      disable                # disable files
      files                  # check file permissions 
      copy                   # make a copy/image of a master file
      processes              # signal / check processes
      module:name            # execute a user-defined module
      )

@end smallexample 

@vindex mountall
@vindex mountinfo
@vindex checktimezone
@vindex netconfig
@vindex childlinks
@vindex singlelinks
@vindex resolve
@vindex unmount
@vindex shellcommands
@vindex editfiles
@vindex addmounts
@vindex directories
@vindex links
@vindex mailcheck
@vindex required
@vindex tidy
@vindex disable
@vindex files 
@vindex processes
@vindex packages
@vindex module

@noindent
Here is a more complete description of the meaning of these
keywords.

@table @code

@item addmounts
causes cfengine to compute which NFS filesystems are missing from the
current host and add them. This includes editing the filesystem table,
creating the mount-directory, if required.  This command relies on
information provided by @code{mountinfo}, so it should normally only be
called after @code{mountinfo}. If the filesystem already appears
to be in the filesystem table, a warning is issued.

@item checktimezone
runs a check on the timezone defined for the shell running
cfengine.

@item directories
executes all the commands defined under the @code{directories}
section of the program. It builds new directories.

@item disable
executes all the commands defined under the @code{disable}
section of the program.

@item editfiles
executes all the commands defined under the @code{editfiles}
section of the program.

@item files
executes all the commands defined under the @code{files}
section of the program.

@item links
executes all the commands defined under the @code{links}
section of the program. 

@item mailcheck
tests for the presence of the NFS-mounted mail spooling directory on the
current host. The name of the mail spool directory is defined in the
@code{mailserver} section of the cfengine program. If the current host
is the same as the mailserver (the host which has the physical spool
directory disk) nothing is done. Otherwise the filesystem table is
edited so as to include the mail directory.

@item module
@cindex Modules, user defined
Normally cfengine's ability to detect the system's condition is limited
to what it is able to determine while excuting predefined
actions. Classes may be switched on as a result of actions cfengine
takes to correct a problem. To increase the flexibility of cfengine, a
mechanism has been introduced in version 1.5 which allows you to include
a module of your own making in order to define or undefine a number of classes.
The syntax

@smallexample
  module:mytests

  "module:mytests arg1 arg2 .."
@end smallexample
declares a user defined module which can potentially set the classes
@var{class1} etc. Classes returned by the module must be declared so
that cfengine knows to pay attention to rules which use these classes
when parsing; this is done using @code{AddInstallable}. If
arguments are passed to the module, the whole string must be quoted like
a shellcommand.  @xref{Writing plugin modules,Writing plugin
modules,Writing plugin modules,cfengine-Tutorial}.  Whether or not these
classes become set or not depends on the behaviour of your module. The
classes continue to apply for all actions which occur after the module's
execution. The module must be owned by the user executing cfengine or
root (for security reasons), it must be named
@file{module:@var{module-name}} and must lie in a special directory,
@xref{moduledirectory}.

@item mountall
mounts all filesystems defined in the hosts filesystem table.  This
causes new NFS filesystems added by @code{addmounts} and
@code{mailcheck} to be actually mounted. This should probably be called
both before @code{mountinfo} and after @code{addmounts} etc.  A short
timeout is placed on this operation to avoid hanging RPC connections
when parsing NFS mounted file systems.

@item mountinfo  
builds internal information about which filesystems are presently
mounted on the current host.  Cfengine assumes that required-filesystems
which are not found need to be mounted. A short timeout is
placed on this operation to avoid hanging RPC connections
when parsing NFS mounted file systems. If this times out,
no further mount operations are considered reliable and are
summarily cancelled.

@item netconfig
checks the netmask, hostname, IP address and broadcast address for the
current host. The correct values for the netmask and broadcast address
are set if there is an error. The defaultroute is matched against the
static routing table and added if no default route exists. This does not
apply to DHCP clients, which set a default route automatically.
@cindex DHCP

@item required
executes all the commands defined under the @code{required}
section of the program. It checks for the absence of
important NFS resources.

@item resolve
checks and corrects the DNS domain name and the order
of nameservers in the file @file{/etc/resolv.conf}.

@item packages
executes commands defined under the @code{packages} section
of the program.  This will query the system's package database
for the specified packages, at the specified versions, set
classes based on whether or not those packages exist, and
optionally install, upgrade or remove those packages using a 
pre-defined package manager command.

@item shellcommands
executes all the commands defined under the @code{shellcommands}
section of the program.

@item tidy
executes all the commands defined under the @code{tidy}
section of the program.

@item unmount
executes all the commands defined under the @code{unmount}
section of the program. The filesystem table is edited
so as to remove the unwanted filesystems and the unmount
operation is executed.

@item processes
executes commands defined under the @code{processes} section
of the program.

@end table

Under normal circumstances this coarse ordering is enough to suit most
purposes.  In some cases you might want to, say, only perform half the
link operations before mounting filesystems and then, say, perform the
remainder.  You can do this (and similar things) by using the idea of
defining and undefining classes. @xref{Defining classes,Defining classes,Defining classes,cfengine-Tutorial}.

The syntax

@smallexample

actionsequence =
   (
   links.firstpass.include
   ...
   links.secondpass
   )
@end smallexample 

@noindent
means that cfengine first executes @code{links} with the classes
@code{firstpass} and @code{include} @emph{defined}.  Later it executes
@code{links} with @code{secondpass} defined.  You can use this method of
adding classes to distinguish more finely the flow of control in
programs.
@cindex Negating classes


A note about style: if you define and undefine lots of classes to do
what you want to do, you might stop and ask yourself if your
@code{groups} are defined as well as they should be.  @xref{groups}.
Programming in cfengine is about doing a lot for only a little
writing.  If you find yourself writing a lot, you are probably not going
about things in the right way.



@c .....................................................
@c SUBSECTION
@c .....................................................

@node addclasses, addinstallable, actionsequence, control
@subsection AddClasses
@cindex Defining classes
@cindex Adding defined classes
@cindex Classes, adding and defining
@vindex AddClasses

@example
   AddClasses  = ( @var{list of identifiers} ) 
@end example

The @code{AddClasses} directive is used to define a list of class
attributes for the current host.  Normally only the hard classes defined
by the system are `true' for a given host.  It is convenient though to
be able to define classes of your own to label certain actions, mainly
so that they can later be excluded so as to cut short or filter out
certain actions.  This can be done in two ways.  @xref{actionsequence}.

To define a list of classes for the current session, you write:

@smallexample
AddClasses = ( exclude shortversion )
@end smallexample 

@noindent
This is equivalent to (though more permanent than) defining
classes on the command line with the @code{-D} option.  
@vindex -D option
@cindex -D option
@cindex Defining classes
You can now use these to qualify actions.  For example

@smallexample

  any.exclude::
      ...
@end smallexample 

Under normal circumstances @code{exclude} is always true --- because you
have defined it to be so, but you can @emph{undefine} it in two ways so
as to prevent the action from being carried out.  One way is to undefine
a class on the command line when you invoke cfengine:
@vindex -N option
@cindex Excluding classes

@example
@cartouche
host#  cfengine -N exclude
@end cartouche
@end example

@noindent
or

@example
@cartouche
host#  cfengine -N exclude.shortversion

host#  cfengine -N a.b.c.d
@end cartouche
@end example

@noindent
These commands run cfengine with the named classes @emph{undefined}.
That means that actions labelled with these classes are excluded during
that run.

Another way to restrict classes is to add a list of classes to be
undefined in the actionsequence.  See next section.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node addinstallable, AllowRedefinitionOf, addclasses, control
@subsection AddInstallable
@cindex Declaring classes
@cindex Defining before use
@vindex AddInstallable

@example
   AddInstallable  = ( @var{list of identifiers} ) 
@end example

Some actions in your cfengine program will be labelled by classes which
only become defined at run time using a @code{define=} option. Cfengine
is not always able to see these classes until it meets them and tries to
save space by only loading actions for classes which is believes will
become defined at some point in the program. This can lead to some
actions being missed if the action is parsed before the place where the
class gets switched on, since cfengine is a one-pass interpreter,.  To
help cfengine determine classes which @emph{might become defined} during
a run, you can declare them in this list. It does no harm to declare
classes here anyway.
Here is an example where you need to declare a class because of the ordering
of the actions. 

@smallexample

control:

    AddInstallable  = ( myclass )

files:

   myclass::

     /tmp/test mode=644 action=fixall

copy: 

     /tmp/foo dest=/tmp/test define=myclass

@end smallexample

@noindent
If we remove the declaration, then when cfengine meets the files
command, it skips it because it knows nothing about the class
@samp{myclass}---when the copy command follows, it is too late.  Remember
that imported files are always parsed after the main program so definitions
made in imported files always come later than things in the main program.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AllowRedefinitionOf, Auditing, addinstallable, control
@subsection AllowRedefinitionOf

Normally cfagent warns about redefinitions of variables during parsing.
This is presumed to be a mistake. To avoid this behaviour, add the name
of the variable to this list, and the warning disappears.

@smallexample
control:

actionsequence = ( copy )

AllowRedefinitionOf = ( cfrep )

cfrep = ( bla )

cfrep = ( blo )

@end smallexample
@cindex Redefinition of macros

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Auditing, AutoDefine, AllowRedefinitionOf, control
@subsection Auditing
@cindex Audit log
@vindex Auditing

If this variable is set to true then cfengine conducts extensive auditing
of its actions to a database in the work directory. When rules are
applied, their locations and policy version are recorded also so that it
is possible to see exactly which rule was applied and when. It is
assumed that the version is recorded as below:
@smallexample

control:

  cfinputs_version = ( 1.2.1 ) 
  Auditing = true

@end smallexample

This variable acts as the global default behaviour and may be
overriden locally by @code{audit=true/false} attributes, where applicable.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AutoDefine, BinaryPaddingChar, Auditing, control
@subsection AutoDefine

@w{}
@smallexample

control:

   hup_syslogd::

     autodefine = ( /etc/syslog.c* )

@end smallexample

Referring to the class that prefixes the command, @code{autodefine} is
a list of file patterns that will define the said class, if a named file is copied
in any statement.  This helps to avoid having to write a large number
of file-specific copy: lines with define=class configured. In the example
above, the class @code{hup_syslogd} would be defined if @file{/etc/syslog.conf}
is copied at any time.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node BinaryPaddingChar, BindToInterface in cfagent, AutoDefine, control
@subsection BinaryPaddingChar

@w{}
@smallexample
BinaryPaddingChar = ( \0 )
@end smallexample
This specifies the type of character used to pad strings of unequal
length in @code{editfiles} during binary editing.  The default value is
the space character, since this is normally used to edit filenames
or text messages within program code.



@c ...........................................
@c SUBSECTION
@c ...........................................

@node BindToInterface in cfagent, ChecksumDatabase in cfagent, BinaryPaddingChar, control
@subsection BindToInterface in cfagent
If this is set to a specific IP address of an IP configured interface,
cfagent will use that address for outgoing connections.  On Multi-homed
hosts this allows one to restrict the traffic to a known interface. An interface must
be configured with an IP address in order to be bound.

This feature is not available for old operating systems.
@cindex Multihomed hosts
@vindex BindToInterface
@cindex Binding to one interface only


@c .....................................................
@c SUBSECTION
@c .....................................................

@node ChecksumDatabase in cfagent, ChecksumPurge, BindToInterface in cfagent, control
@subsection ChecksumDatabase in cfagent

@w{}
@smallexample
ChecksumDatabase = ( /var/cfengine/cfdb )

@end smallexample

@cindex ChecksumDatabase
@cindex Message digests
@cindex Hashes of files
@cindex Tripwire functionality
@vindex ChecksumDatabase
If this filename is defined, cfengine will use it to store
message digests (i.e. cryptographic checksums) of files
for security purposes, @xref{files}, @code{checksum=}.

This option was deprecated in 2.1.22.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node ChecksumPurge, ChecksumUpdates, ChecksumDatabase in cfagent, control
@subsection ChecksumPurge

@w{}
@smallexample
ChecksumPurge = ( on )

@end smallexample

@cindex ChecksumPurge
@vindex ChecksumPurge
This variable defaults to `off'. If set to true, cfagent will
look at all of the registered files in the database and check
whether thet still exist. If the file no longer exists, it
is removed from the database and a warning is issued.

To purge files now and then, but at no particular time, one could do
something like this:

@smallexample

strategies:

 @{ purging

 NowAndThen: 1
 ElseWhen:   49
 @}

control:

 NowAndThen::

   ChecksumPurge = ( on )


@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node ChecksumUpdates, CompressCommand, ChecksumPurge, control
@subsection ChecksumUpdates

@w{}
@smallexample
ChecksumUpdates = ( on )

@end smallexample

@cindex ChecksumUpdates
@vindex ChecksumUpdates
This variable defaults to `off'. If set to true, cfagent will
automatically update the checksum of a file, if it changes on the disk.
This means that a security warning will be issued only once
about files which have changed, and the changed version will be re-registered
as the correct version. This option could be switched on after a
system upgrade, for instance, in order to update the database, and then
switched to `off' again to reduce the risk of missing a security
alert. Alternatively, if you are confident that the first message is
sufficient, it can be left as `on' so that only one message is
given.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node CompressCommand, childlibpath, ChecksumUpdates, control
@subsection CompressCommand

Specified the name of a program that is used in the files @code{action=compress}
attribute.

@w{}
@smallexample
CompressCommand = ( /usr/bin/gzip )

@end smallexample

@cindex CompressCommand
@vindex CompressCommand


@c .....................................................
@c SUBSECTION
@c .....................................................

@node childlibpath, copylinks, CompressCommand, control
@subsection ChildLibPath

Sets a value for LD_LIBRARY_PATH in child processes:
@example

 childlibpath = ( /usr/local/lib:/local/mysql/lib )

@end example
Note that the variables LD_LIBRARY_PATH is special. This
library path is needed to run processes as children of cfengine.
Often, if the agent is started from cron (which is started by init),
there is no suitable library path set, and shellcommands will
fail with strange errors about not being able to load shared
objects. Setting a library path here is a useful way of
correcting this problem.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node copylinks, defaultcopytype, childlibpath, control
@subsection CopyLinks
This list is used to define a global list of names or patterns
which are to be copied rather than linked symbolically. For example

@smallexample
CopyLinks = ( *.config )
@end smallexample
The same facility can be specified for each individual
link operation using the @code{copy} option @xref{links}.
Copying is performed using a file age comparison.

Note that all entries defined under a specified class
are valid only as long as that class is defined. For instance

@smallexample
  @var{class}::

      CopyLinks = ( @var{pattern} )
@end smallexample
@noindent
would define a pattern which was only valid when
@var{class} is defined.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node defaultcopytype, defaultpkgmgr, copylinks, control
@subsection DefaultCopyType

This parameter determines the default form of copying for all copy operations
parsed after this variable. The legal values are
@code{ctime} (intial default), @code{mtime}, @code{checksum} and @code{binary}.
e.g.

@smallexample

 DefaultCopyType = ( mtime )

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................

@node defaultpkgmgr, deletenonuserfiles, defaultcopytype, control
@subsection DefaultPkgMgr

Sets the default value of the @code{pkgmgr} attribute for
@code{packages} items.

@w{}
@smallexample
DefaultPkgMgr = ( rpm )
@end smallexample

By default, this variable is not set, meaning there will be no
package manager selected, and each item in the @code{packages}
section must specify its own package manager, or it will not be
checked.  For information on the values of this variable, @xref{packages}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node deletenonuserfiles, deletenonownerfiles, defaultpkgmgr, control
@subsection DeleteNonUserFiles

If this parameter is set to true, cfengine will delete files 
which do not have a name belonging to a known user id.

@smallexample
DeleteNonUserFiles = ( true )

SpoolDirectories = ( /var/spool/cron/crontabs )
@end smallexample

@cindex DeleteNonUserMail DeleteNonUserFiles
This is an generalization of DeleteNonUserMail and makes it redundant.
it is formally executed as a part of the ``tidy'' action.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node deletenonownerfiles, deletenonusermail, deletenonuserfiles, control
@subsection DeleteNonOwnerFiles

If this parameter is set to true, cfengine will delete files on mailservers
whose names do not correspond to a known user name, but might be owned by a
known user. 

@smallexample
DeleteNonOwnerFiles = ( true )

SpoolDirectories = ( /var/spool/cron/crontabs )
@end smallexample

@cindex DeleteNonOwnerMail
@cindex DeleteNonUserFiles

This is an generalization of DeleteNonOwnerMail and makes it redundant.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node deletenonusermail, deletenonownermail, deletenonownerfiles, control
@subsection DeleteNonUserMail

If this parameter is set to true, cfengine will delete mail files on mailservers
which do not have a name belonging to a known user id. This does not
include lock files.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node deletenonownermail, domain, deletenonusermail, control
@subsection DeleteNonOwnerMail

If this parameter is set to true, cfengine will delete files on mailservers
whose names do not correspond to a known user name, but might be owned by a
known user. 

@c .....................................................
@c SUBSECTION
@c .....................................................

@node domain, dpkginstallcommand, deletenonownermail, control
@subsection domain
@cindex domain
@vindex domain

@example
  domain = ( @var{domain name} )
@end example

This variable defines the domainname for your site.  You must define it
here, because your system might not know its domainname when you run
cfengine for the first time.  The domainname can be used as a cfengine
variable subsequently by referring to $(domain).  The domainname
variable is used by the action @code{resolve}. The domain is also used
implicitly by other matching routines. You should define the domain as
early as possible in your configuration file so as to avoid problems,
especially if you have the strange practice of naming hosts with their
fully qualified host names since groups which use fully qualified names
can fail to be defined if cfengine is not able to figure out the domain name.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node dpkginstallcommand, dryrun, domain, control
@subsection DPKGInstallCommand

Sets the command used to install packages that need to be installed
under the DPKG package manager.

@smallexample
DPKGInstallCommand = ( "/usr/bin/pkgmgr %s" )
@end smallexample

By default, this variable is not set, meaning that any packages with
action=install will NOT be installed if installation is required.  Note
the "'s around the string, and the %s is replaced with the name of the
package to be installed.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node dryrun, editbinaryfilesize, dpkginstallcommand, control
@subsection DryRun
@cindex DryRun
@vindex DryRun

@w{}
@smallexample

  DryRun = ( @var{on/}@b{off} )

@end smallexample

This variable has the same effect as the command line options
@kbd{--dry-run} or @kbd{-n}. It tells cfengine to only report
what it should do without actually doing it.

@smallexample

 @var{classes}::

   DryRun = ( on )

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................

@node editbinaryfilesize, editfilesize, dryrun, control
@subsection editbinaryfilesize
@cindex Restricting the size of binary files to be edited
@vindex editbinaryfilesize

@example
   EditBinaryFileSize  = ( @var{size} ) 
@end example

Cfengine will refuse to edit a file which is larger than the value of
@code{editbinaryfilesize} in bytes.  This is to prevent possible
accidents from occurring.  The default value for this variable is 10000000
bytes.  If you don't like this feature, simply set the value to be a
very large number or to zero.  If the value is zero, cfengine will
ignore it.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node editfilesize, emptyresolvconf, editbinaryfilesize, control
@subsection editfilesize
@cindex Restricting the size of files to be edited
@vindex editfilesize

@example
   EditfileSize  = ( @var{size} ) 
@end example

This variable is used by cfengine every time it becomes necessary to
edit a file.  Since file editing applies only to text files, the files
are probably going to be relatively small in most cases.  Asking to edit
a very large (perhaps binary) file could therefore be the result of an
error.

A check is therefore made as a security feature.  Cfengine will refuse
to edit a file which is larger than the value of @code{editfilesize} in
bytes.  This is to prevent possible accidents from occurring.  The
default value for this variable is 10000 bytes.  If you don't like this
feature, simply set the value to be a very large number or to zero.
If the value is zero, cfengine will ignore it.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node emptyresolvconf, exclamation, editfilesize, control
@subsection EmptyResolvConf
@cindex Emptying old nameservers from @file{/etc/resolv.conf}
@vindex EmptyResolvConf

@example
   EmptyResolvConf  = ( true ) 
@end example

Normally cfengine does not tidy up old entries in the @file{/etc/resolv.conf}
file. This option causes cfengine to remove all existing content from the
file.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node exclamation, excludecopy, emptyresolvconf, control
@subsection Exclamation

This variable defaults to ``on''. If set to ``off'', no exclamation marks
(Br. pling, Am: shriek) are printed during security alerts, e.g. for
checksum violations.

@example
   Exclamation  = ( off ) 
@end example

@vindex Exclamation
@cindex Checksum warning, turning off exclamation
@cindex Exclamation marks, turning off

@c .....................................................
@c SUBSECTION
@c .....................................................

@node excludecopy, excludelinks, exclamation, control
@subsection ExcludeCopy
This list is used to define a global list of names or patterns
which are to be excluded from copy operations. For example

@smallexample
 ExcludeCopy = ( *~ *% core )
@end smallexample
The same facility can be specified for each individual
link operation using the @code{exclude} option @xref{copy}.

Note that all entries defined under a specified class
are valid only as long as that class is defined. For instance

@smallexample
  @var{class}::

      ExcludeCopy = ( @var{pattern} )
@end smallexample
@noindent
would define a pattern which was only valid when
@var{class} is defined.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node excludelinks, ExpireAfter, excludecopy, control
@subsection ExcludeLink
This list is used to define a global list of names or patterns
which are to be excluded from linking operations. For example

@smallexample
 ExcludeLink = ( *~ *% core )
@end smallexample
The same facility can be specified for each individual
link operation using the @code{exclude} option @xref{links}.

Note that all entries defined under a specified class
are valid only as long as that class is defined. For instance

@smallexample
  @var{class}::

      ExcludeLink = ( @var{pattern} )
@end smallexample
@noindent
would define a pattern which was only valid when
@var{class} is defined.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node ExpireAfter, FreeBSDInstallCommand, excludelinks, control
@subsection ExpireAfter

If you change the value of this parameter, it should be one of the
first things you do in your configuration script.

This parameter controls the global value of the ExpireAfter parameter.
@xref{Spamming and security,Spamming and security,Spamming and
security,cfengine-Tutorial}. This parameter controls the maximum time
in minutes which a cfengine action is allowed to live. After this time
a second cfengine agent will try to kill the cfengine which seems to
have hung and attempt to restart the action. This is different from a TimeOut,
where an internal alarm interrupt is used.

@cartouche

@w{}
@smallexample
 
 ExpireAfter = ( @var{time-in-minutes} )

@end smallexample
@end cartouche

@noindent
This parameter may also be set per action in the action
sequence by appending a pseudo-class called @code{ExpireAfter@var{time}}.
For instance,

@smallexample
 
 actionsequence = ( copy.ExpireAfter15 )

@end smallexample

@noindent
sets the expiry time parameter to 15 minutes for this copy command.
This method should be considered old and deprecated however.
As of version 2.1.0, you can define the expiry time on a per-command basis,
as options of the form @code{expireafter=10}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node FreeBSDInstallCommand, FreeBSDRemoveCommand, ExpireAfter, control
@subsection FreeBSDInstallCommand

Sets the path to `pkg_add' which is used to install packages that need
to be installed under FreeBSD.

@smallexample

     FreeBSDInstallCommand = ( "/usr/sbin/pkg_add -r %s" )

@end smallexample

By default, this variable is not set, meaning that any packages with
action=install will NOT be installed. Note the quotes around the string,
and the @code{%s} is replaced with the name of the package to be installed.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node FreeBSDRemoveCommand, FullEncryption, FreeBSDInstallCommand, control
@subsection FreeBSDRemoveCommand

Sets the path to `pkg_delete' which is used to remove packages that need
to be uninstalled under FreeBSD.

@smallexample

     FreeBSDRemoveCommand = ( "/usr/sbin/pkg_delete %s" )

@end smallexample

By default, this variable is set to /usr/sbin/pkg_delete, meaning that any
packages with action=remove will be removed.  Note the quotes around the 
string, and the @code{%s} is replaced with the name of the package to be installed.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node FullEncryption, homepattern, FreeBSDRemoveCommand, control
@subsection FullEncryption

From version 2.1.22. This is false for protocol compatability with older
servers.

If this is set to true, directory filenames are encrypted in addition
to file contents. If transferred data are not especially secret or
travel over public networks this is a waste of CPU time. In high
security environments it provides full privacy of data transmission.

@cartouche

@w{}
@smallexample
 
 FullEncryption = ( true )

@end smallexample
@end cartouche


@c .....................................................
@c SUBSECTION
@c .....................................................

@node homepattern, HostnameKeys in cfagent, FullEncryption, control
@subsection HomePattern
@cindex Home path
@cindex Path to home directories
@vindex HomePattern

@example
   HomePattern  = ( @var{list of patterns} ) 
@end example


The @code{homepattern} variable is used by the cfengine model for
mounting nfs filesystems.  @xref{NFS resources,NFS resources,NFS
resources,cfengine-Tutorial}.  It is also used in the evaluation of the
pseudo variable @code{home}, See @ref{files}, @ref{tidy}.

@code{homepattern} is in fact a list and is used like a wildcard or
@emph{pattern} to determine which filesystems in the list of mountables
are home directories.  @xref{mountables}.  This relies on your sticking
to a rigid naming convention as described in the first reference above.

For example, you might wish to mount (or locate directly if you are not
using a separate partition for home directories) your home directories
under @code{mountpattern} in directories @code{u1}, @code{u2} and so on.
In this case you would define @code{homepattern} to match these numbers:

@cindex Wildcards in homepattern
@cindex Searching for home directories

@w{}
@smallexample
homepattern = ( u? )
@end smallexample 

@noindent
Cfengine now regards any directory matching
@code{$(mountpattern)/u?} as being a user login directory.

Suppose you want to create mount home directories under
@code{$(mountpattern)/home} and make subdirectories for staff and
students.  Then you would be tempted to write:

@smallexample
 HomePattern = ( home/staff home/students )
@end smallexample 

@noindent
Unfortunately this is not presently possible. (This is, in principle,
a bug which should be fixed in the future.) What you can do instead is
to achieve the same this as follows:

@smallexample
 MountPattern = ( /$(site)/$(host) /$(site)/$(host)/home )
 HomePattern = ( staff students )
@end smallexample 

@c .....................................................
@c SUBSECTION
@c .....................................................

@node HostnameKeys in cfagent, IfElapsed in cfagent, homepattern, control
@subsection HostnameKeys in cfagent

If this variable is set to true/on, it causes cfagent to
lookup and store trusted public keys according to their
DNS fully qualified host name, instead of using the IP address.
This can be useful in environments where hosts do not have fixed
IP addresses, but do have fixed hostnames.

@smallexample

  HostnameKeys = ( on )

@end smallexample
This method of storing keys is not recommended for sites with
fixed IP addresses, since it removes one security barrier
from a potential attacker by potentially allowing DNS spoofing.

Note that there is a corresponding variable to be set in @file{cfrun.hosts}
which must be set for consistency.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node IfElapsed in cfagent, IgnoreFriendRegex, HostnameKeys in cfagent, control
@subsection IfElapsed in cfagent

If you change the value of this parameter, it should be one of the
first things you do in your configuration script.

This parameter controls the global value of the IfElapsed parameter,
@xref{Spamming and security,Spamming and security,Spamming and
security,cfengine-Tutorial}. This parameter controls the minimum time
which must have elapsed for an action in the action sequence before
which it will be executed again.

@cartouche

@w{}
@smallexample
 
 IfElapsed = ( @var{time-in-minutes} )

@end smallexample
@end cartouche

@noindent
This parameter may also be set per action in the action
sequence by appending a pseudo-class called @code{IfElapsed@var{time}}.
For instance,

@smallexample
 
 ActionSequence = ( copy.IfElapsed15 )

@end smallexample

@noindent
sets the elapsed time parameter to 15 minutes for this copy command.
This method should be considered old and deprecated however.
As of version 2.1.0, you can define the expiry time on a per-command basis,
as options of the form @code{ifelapsed=15}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node IgnoreFriendRegex, IgnoreInterfaceRegex, IfElapsed in cfagent, control
@subsection FriendIgnoreRegex

Use this regular expression to suppress FriendStatus warnings
for matching hosts. e.g.
@smallexample

     IgnoreFriendRegex = ( "2001:700:.*|host1|host2" )

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................

@node IgnoreInterfaceRegex, Inform, IgnoreFriendRegex, control
@subsection IgnoreInterfaceRegex

Use this regular expression to delete class information
about interfaces that you do not want to see on a host.
This is useful for tamig virtual machines and their multitudinous interfaces.

@smallexample

     IgnoreInterfaceRegex = ( "vm.*" )

@end smallexample
@cindex Virtual interfaces
@cindex Interface classes
@vindex IgnoreInterfaceRegex

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Inform, interfacename, IgnoreInterfaceRegex, control
@subsection Inform

@w{}
@smallexample

  Inform = ( @var{on/}@b{off} )

@end smallexample

This variable switches on the output level whereby cfengine
reports changes it makes during a run. Normally only
urgent messages or clear errors are printed. Setting
@code{Inform} to @code{on} makes cfengine report on
all actions not explicitly cancelled with a `silent' option.
To set this output level one writes:

@smallexample

 @var{classes}::

   Inform = ( on )

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node interfacename, fileextension, Inform, control
@subsection InterfaceName
@cindex InterfaceName
@vindex InterfaceName
@cindex Interface name, redefining by class

If you have an operating system which is installed on some
non-standard hardware, you might have to specifically set the
name of the network interface. For example:

@smallexample

  control:

    nextstep.some::

       InterfaceName = ( en0 )

    nextstep.others::

       InterfaceName = ( ec0 ) 

@end smallexample
@noindent
It is only necessary to set the interface name in this fashion
if you have an operating system which is running on special
hardware. Most users will not need this.
The choice set here overrides the system defaults and the
choices made in the @file{cfrc} file, @xref{cfrc resource file}.




@c .....................................................
@c SUBSECTION
@c .....................................................

@node fileextension, lastseen, interfacename, control
@subsection FileExtensions

This list may be used to define a number of extensions
which are regarded as being plain files by the system.
As part of the general security checking cfengine will
warn about any directories which have names using
these extensions. They may be used to conceal directories.

@smallexample

  FileExtensions = ( c o gif jpg html )

@end smallexample
@vindex FileExtensions
@cindex Directories, hidden


@c .....................................................
@c SUBSECTION
@c .....................................................

@node lastseen, lastseenexpireafter, fileextension, control
@subsection LastSeen

This option is true by default. If set to off or false it prevents cfengine
and/or cfservd from learning about last times hosts were observed
connecting to one another. Some users with broken resolvers (particularly
in view of the change over to IPv6 compatible libraries) might find this
useful when processes appear to hang on connecting.
@cindex Broken resolver
@cindex LastSeen
@cindex Hanging processes

@w{}
@smallexample

  LastSeen = ( off )

@end smallexample
@vindex LastSeen


@c .....................................................
@c SUBSECTION
@c .....................................................

@node lastseenexpireafter, linkcopies, lastseen, control
@subsection LastSeenExpireAfter

This value (in days) sets the time after which unseen friend hosts
are purged from the `last seen' database, as viewed by the @code{FriendStatus}
function, @xref{alerts}.

@smallexample

  LastSeenExpireAfter = ( 2 )

@end smallexample
@vindex LastSeenExpireAfter
@cindex Last Seen database


@c .....................................................
@c SUBSECTION
@c .....................................................

@node linkcopies, LogDirectory, lastseenexpireafter, control
@subsection LinkCopies

This list is used to define a global list of names or patterns
which are to be linked symbolically rather than copied. For example

@smallexample
excludelinks = ( *.gif *.jpg )
@end smallexample
The same facility can be specified for each individual
link operation using the @code{symlink} option @xref{copy}.

Note that all entries defined under a specified class
are valid only as long as that class is defined. For instance

@smallexample
  @var{class}::

      LinkCopies = ( @var{pattern} )
@end smallexample
@noindent
would define a pattern which was only valid when
@var{class} is defined.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node LogDirectory, LogTidyHomeFiles, linkcopies, control
@subsection LogDirectory

This is now deprecated.

Specify an alternative directory for keeping cfengine's
log data. This defaults to @file{/var/run/cfengine} or
@file{/var/cfengine}.

@w{}
@smallexample

  LogDirectory = ( /var/cfengine )

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node LogTidyHomeFiles, moduledirectory, LogDirectory, control
@subsection LogTidyHomeFiles

@w{}
@smallexample

  LogTidyHomeFiles = ( off ) 

@end smallexample

If set to ``off'', no log is made of user files, in their
home directories, of the files which are tidied by cfengine.

@cindex Tidy log files for users


@c .....................................................
@c SUBSECTION
@c .....................................................

@node moduledirectory, mountpattern, LogTidyHomeFiles, control
@subsection moduledirectory
@cindex Module directory
@cindex Directory for cfengine modules
@vindex moduledirectory


@example
   moduledirectory  = ( @var{directory for plugin modules} ) 
@end example

This is the directory where cfengine will look for plug-in modules
for the actionsequence, @xref{actionsequence}. Plugin modules
may be used to activate classes using special algorithms. 
@xref{Writing plugin modules,Writing plugin modules,Writing plugin modules,cfengine-Tutorial}.
This variable defaults to @file{/var/cfengine/modules} for privileged users and
to @file{$HOME)/.cfengine/modules} for non-privileged users.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node mountpattern, netmask, moduledirectory, control
@subsection mountpattern
@cindex Mount paths
@cindex Path to mounted filesystems
@vindex mountpattern

@example
   mountpattern  = ( @var{mount-point} ) 
@end example


The @code{mountpattern} list is used by the cfengine model for mounting
nfs filesystems.  @xref{NFS resources,NFS resources,NFS
resources,cfengine-Tutorial}.  It is also used in the evaluation of the
pseudo variable @code{home}, See @ref{files}, @ref{tidy}.

It is used together with the value of @code{homepattern} to locate and
identify what filesystems are local to a given host and which are
mounted over the network.  For this list to make sense you need to
stick to a rigid convention for mounting your filesystems under a single
naming scheme as described in the section mentioned above.  If you
follow the recommended naming scheme then you will want to set the value
of mountpattern to

@smallexample
mountpattern = ( /$(site)/$(host) )
@end smallexample 

@noindent
which implies that cfengine will look for local disk partitions under a
unique directory given by the name of the host and site.  Any
filesystems which are physically located on the current host lie in this
directory.  All mounted filesystems should lie elsewhere. If you
insist on keeping mounted file systems in more than one location, you
can make a list like this:

@smallexample
mountpattern = ( /$(site)/users /$(site)/projects )
@end smallexample 

@c .....................................................
@c SUBSECTION
@c .....................................................

@node netmask, nonalphanumfiles, mountpattern, control
@subsection netmask
@cindex netmask
@vindex netmask

@example
   netmask = ( @var{aaa.bbb.ccc.ddd} )
@end example

The netmask variable defines the partitioning of the subnet addresses on
your network.  Its value is defined by your network administrator.  On
most systems it is likely to be @code{255.255.255.0}.  This is used to
configure the network interface in @code{netconfig}.
@xref{actionsequence}.


@cindex Domain name
@cindex IP address
@cindex Internet address
@cindex Netmask
@cindex Subnet mask
Every host on the internet has its own unique address.  The addresses
are assigned hierarchically.  Each network gets a @emph{domain name} and
can attach something like 65,000 hosts to that network.  Since this is
usually too many to handle in one go, every such network may be divided
up into subnets.  The administrator of the network can decide how the
division into subnets is made.  The decision is a trade-off between
having many subnets with few hosts, or many hosts on few subnets.  This
choice is made by setting the value of a variable called @code{netmask}.
The netmask looks like an internet address.  It takes the form:

@example

   aaa.bbb.ccc.mmm

@end example

@noindent
The first two numbers @samp{aaa.bbb} are the address of the domain.  The
remainder @samp{ccc.mmm} specifies both the subnet and the hostname.
The value of @code{netmask} tells all hosts on the network: how many of
the bits in the second half label different subnets and how many label
different hosts on each of the subnets?

The most common value for the netmask is @samp{255.255.255.0}.  It is
most helpful to think of the netmask in terms of bits.  Each base-10
number between 0-255 represents 8 bits which are either set or not set.
Every bit which is set is a network address and every bit which is zero
is part of a host address.  The first two parts of the address
@samp{255.255} always takes these values.  If the third number is
@samp{255}, it means that the domain is divided up into 256 sub networks
and then the remaining bits which are zero can be used to give 255
different host addresses on each of the subnets.

If the value had been @samp{255.255.255.254}, the network would be
divided up into @math{2^15} subnets, since fifteen of the sixteen bits
are one.  The remaining bit leaves enough room for two addresses 0 and
1.  One of those is reserved for @emph{broadcasts} to all hosts, the
other can be an actual host --- there would only be room for one host
per subnet.  This is a stupid example of course, the main point with the
subnet mask is that it can be used to trade subnets for hosts per
subnet.  A value of @samp{255.255.254.0} would allow 128 different
subnets with @math{2*256-1 = 511} hosts on each.

We needn't be concerned with the details of the netmask here.  Suffice
it to say that its value is determined for your entire domain by the
network administrator and each host has to be told what the value is.

Each host must also know what convention is used for the @emph{broadcast
address}.  This is an address which hosts can send to if they wish to
send a message to every other host on their subnet simultaneously.  It is
used a lot by services like NIS to ask if any hosts are willing to
perform a particular service.  There are two main conventions for the
broadcast address: address zero (all host bits are zero) and the highest
address on the subnet (all host bits are ones).  The convention can be
different on every subnet and it is decided by the network
administrator.  When you write a cfengine program you just specify the
convention used on your subnet and cfengine works out the value of the
broadcast address from the netmask and the host address
@xref{broadcast}.  Cfengine works out the value of the broadcast address
using the value of the netmask.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node nonalphanumfiles, nfstype, netmask, control
@subsection NonAlphaNumFiles

If enabled, this option causes cfengine to detect and
disable files which have purely non-alphanumeric
filenames, i.e. files which might be accidental or
deliberately concealed. The files are then marked
with a suffix @code{.cf-nonalpha} and are rendered
visible.

@smallexample

  NonAlphaNumFiles = ( on )

@end smallexample

These files can then be tidied by searching for
the suffix. Note that alphanumeric means
ascii codes less than 32 and greater than 126.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node nfstype, PortageInstallCommand, nonalphanumfiles, control
@subsection nfstype
@cindex nfs
@cindex nfstype
@vindex nfstype

@example
   nfstype = ( @var{nfs-type} ) 
@end example

This variable is included only for future expansion.  If you do not
define this variable, its value defaults to ``nfs''.

At present cfengine operates only with NFS (the network file system).
When cfengine looks for network file systems to mount, it adds lines in
the filesystem table (@samp{/etc/fstab},@samp{/etc/checklist} etc.)  to
try to mount filesystems of type ``nfs''.  In principle you might want
to use a completely different system for mounting filesystems over the
network, in which case the `mount type' would not be ``nfs'' but
something else.

At the time of writing certain institutions are replacing NFS with AFS
(the Andrew filesystem) and DFS (from the distributed computing
environment).  The use of these filesystems really excludes the need to
use the mount protocol at all.  In other words if you are using AFS or
DFS, you don't need to use cfengine's mounting commands at all.
@cindex AFS
@cindex Andrew filesystem
@cindex DFS

@c .....................................................
@c SUBSECTION
@c .....................................................

@node PortageInstallCommand, repchar, nfstype, control
@subsection PortageInstallCommand

Sets the path to `emerge' which is used to install packages that need
to be installed under Gentoo Portage.

@smallexample

 gentoo.some::
     DefaultPkgMgr = ( portage )
     PortageInstallCommand = ( "/usr/bin/emerge --nocolor %s" )

 gentoo.other::

    DefaultPkgMgr = ( portage )
    PortageInstallCommand = ( "/usr/lib/portage/bin/emerge --color=n %s"

@end smallexample

By default, this variable is not set, meaning that any packages with
action=install will NOT be installed if installation is required. Note
the quotes around the string, and the @code{%s} is replaced with the name
of the package to be installed.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node repchar, repository, PortageInstallCommand, control
@subsection RepChar

@example
   RepChar = ( @var{character} )
@end example

The value of this variable determines the characters which is used by
cfengine in creating the unique filenames in the file
repository. Normally, its value is set to @samp{_} and each @samp{/} in
the path name of the file is changed to @samp{_} and stored in the
repository. If you prefer a different character, define it here. Note
that the character can be quoted with either single or double quotes in
order to encompass spaces etc.
@vindex RepChar
@cindex Repository filenames, changing
@mbindex Changing repository name conventions

@c .....................................................
@c SUBSECTION
@c .....................................................

@node repository, RPMcommand, repchar, control
@subsection Repository


@example
   Repository  = ( @var{directory} ) 
@end example

Defines a special directory where all backup and junk
files are collected. Files are assigned a unique filename
which identifies the path from which they originate.
This affects files saved using @code{disable}, @code{copy},
@code{links} and @code{editfiles} @xref{Disabling and the file repository,Disabling and the file repository,Disabling and the file repository,cfengine-Tutorial}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node RPMcommand, rpminstallcommand, repository, control
@subsection RPMcommand

The default value of the Red Hat Package manager command @file{/bin/rpm} can be altered
for non-standard systems with this variable.
@example
RPMcommand = ( /usr/bin/rpm )


@end example

@c .....................................................
@c SUBSECTION
@c .....................................................

@node rpminstallcommand, schedule, RPMcommand, control
@subsection RPMInstallCommand

Sets the command used to install packages that need to be installed
under the RPM package manager.

@smallexample
RPMInstallCommand = ( "/usr/bin/pkgmgr %s" )
@end smallexample

By default, this variable is not set, meaning that any packages with
action=install will NOT be installed if installation is required.  Note
the quotes around the string, and the @code{%s} is replaced with the name
of the package to be installed.

@smallexample
control:
  DefaultPkgMgr = ( rpm )
  RPMInstallCommand = ( "/usr/bin/yum -d 0 -e 0 -y install %s" )
  
  # This would remove all dependencies (!)
  #
  # RPMRemoveCommand = ( "/usr/bin/yum -d 0 -e 0 -y remove %s" )

  # This might be less drastic

   RPMRemoveCommand = ( "/bin/rpm -e --nodeps %s" )

packages:

# this will remove this package regardless of version.

  some_rpm_name version=0:0.0 cmp=ge action=remove   
  

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node schedule, secureinput, rpminstallcommand, control
@subsection Schedule
@cindex scheduling
@vindex scheduling


@example
   schedule  = (  Min00_05 Min30_35 @var{time class} ) 
@end example

When @code{cfexecd} is used in daemon mode, it defaults to running
once an hour, on the hour, i.e..
 @example
   schedule  = (  Min00_05 ) 
@end example
This can be extended to make the agent run more often. The time
specifiers are cfengine classes, and are written as intervals of time
rather the precise times.  Cfengine's time resolution is purposely
limited to five minutes because the auto-correlation time of user
resources is generally greater than this. Thus, it is assumed that
precision timing is not required and the start time of cfengine, when
scheduled in daemon mode, is not better than a few minutes.  The daemon
does not require precision, but offers many other strategic
features for load balancing and security.

Other time classes can be used in the schedule list, but note
that cfexecd will not run the agent more than once every five minutes.
This is treated as a fundamental granularity.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node secureinput, sensiblecount, schedule, control
@subsection SecureInput
@cindex Secure input
@vindex SecureInput


@example
   SecureInput = ( on )
@end example

If this is set cfengine will not import
files which are not owned by the uid running the program, or
   which are writable by groups or others.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node sensiblecount, sensiblesize, secureinput, control
@subsection SensibleCount
@cindex Sensible limits on files in a directory
@vindex SensibleCount

@example
   SensibleCount  = ( @var{count} ) 
@end example

This variable is used by the action @code{required}.  It defines for
cfengine what you consider to be the minimum number of files in a
`required' directory.  If you declare a directory as being required,
cfengine will check to see if it exists.  Then, if the directory
contains fewer than the value of @code{sensiblecount} files, a warning
is issued.  The default value for this variable is 2.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node sensiblesize, showactions, sensiblecount, control
@subsection SensibleSize
@cindex Sensible file sizes
@vindex SensibleSize

@example
   SensibleSize  = ( @var{size} ) 
@end example

This variable is used by the action @code{required}.  It defines for
cfengine what you consider to be the minimum size for a `required' file.
If you declare a file as being required, cfengine will check to see if
the file exists.  Of course, the file may exist but be empty, so the
size of the file is also checked against this constant.  If the file is
smaller than the value of @code{sensiblesize} a warning is issued.  The
default value for this variable is 1000 bytes. 

@c .....................................................
@c SUBSECTION
@c .....................................................

@node showactions, singlecopy, sensiblesize, control
@subsection ShowActions

@vindex ShowActions

@example
   ShowActions  = ( @var{on} ) 
@end example

This causes cfengine to produce detailed output of what action is
being carried out as part of the prefix information during output.
This is intended only for third party tools which collect and parse
the cfengine output. It will be of little interest to humans.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node singlecopy, site, showactions, control
@subsection SingleCopy

@smallexample

	singlecopy = ( path_and_filename_wildcard )

@end smallexample

If a @code{singlecopy} pattern is defined the behavior of copy: is
modified so that a given destination file, matching the pattern, will
only be updated once. In other words, if someone tries to copy more
then one source file to the same location, the destination will not be
overwritten in the same run. If the path name and wildcard is any of '*',
'on' or 'true', then the list applies to all files.
For example:

@smallexample
control:

  actionsequence = ( copy )

  singlecopy = ( /tmp/* )

  addinstallables = ( zzz )

 zzz::

  autodefine = ( /tmp/* )

copy:

 /etc/passwd dest=/tmp/destination type=binary
 /etc/group  dest=/tmp/destination type=binary

alerts:

 zzz::
  
  "Copied something in /tmp"

@end smallexample

Note (Warning) that this feature has several problems. It assumes an order
dependence that cfengine generally tries to avoid. The first copy that
takes place wins. Also, if files are locked at different times, this
can result in oscillations between several different source files.
e.g.

@smallexample

copy:

 /etc/passwd dest=/tmp/bla type=binary ifelapsed=2
 /etc/group  dest=/tmp/bla type=binary ifelapsed=1

@end smallexample

In order to avoid explicit looping, cfengine assumes that a file has
been copied even if no actual copy took place -- i.e. as long as a
file is apparently up to date, that counts as a valid copy update and the
promise/action is considered done. If this were not the case, then the
following promises would still be in line for execution and cfengine
would loop between the different versions on subsequent invocations.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node site, SkipIdentify, singlecopy, control
@subsection site/faculty
@cindex site
@vindex site

@example
  site    = ( @var{sitename} )
  faculty = ( @var{facultyname} )
@end example

This variable defines a convenient name for your site configuration.  It
is useful for making generic rules later on, because it means for
instance that you can define the name of a directory to be

@smallexample
/$(site)/$(host)/local
@end smallexample 

@noindent
without having to redefine the rule for a specific site.  This is a
handy trick for making generic rules in your files which can be imported
into a configuration for any site.

@code{faculty} is a synonym for @code{site}.  The two names
may be used interchangeably.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node SkipIdentify, Smtpserver, site, control
@subsection SkipIdentify

@example
  SkipIdentify = ( true )
@end example

This is the client side directive corresponding to the server
directive @code{SkipVerify}. It tells cfengine not to assume that
the client is registered in the Domain Name Service (DNS). Sometimes
the assumption of DNS registration can break connectivity between hosts,
particularly if firewalls or Network Address Translation is in use.

@cindex SkipIdentify
@cindex Network Address Translation

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Smtpserver, SplayTime, SkipIdentify, control
@subsection smtpserver

@example
  smtpserver = ( @var{mailhost} )
@end example

This variable specified the destination for Email sent by cfexecd.
@cindex Mailhost
@cindex smtpserver


@c .....................................................
@c SUBSECTION
@c .....................................................

@node SplayTime, split, Smtpserver, control
@subsection SplayTime

@example
  SplayTime = ( @var{time-in-minutes} )
@end example

This variable is used to set the maximum time over
which cfengine will share its load on a server,
@xref{Splaying host times,Splaying host times,Splaying host times,cfengine-Tutorial}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node split, spooldirectories, SplayTime, control
@subsection Split

@example
   Split  = ( @var{character} ) 
@end example

The value of this variable is used to define the list separator in
variables which are expected to be treated as lists. The default value
of this variable is the colon @samp{:}.  Cfengine treats variables
containing this character as lists to be broken up and iterated over,
@xref{Iteration over lists}.

This typically allows communication with PATH-like 
environment variables in the shell.
@cindex split
@cindex Iteration over lists
@mbindex Iterating over lists
@vindex split

@c .....................................................
@c SUBSECTION
@c .....................................................

@node spooldirectories, suninstallcommand, split, control
@subsection SpoolDirectories
@cindex SpoolDirectories
@vindex SpoolDirectories

A list of additional spool directories for cfengine to police. In these
directories, filenames should correspond to existing users of the
system.  When users lost their accounts, this list plus the mail spool
directory will be checked for files owned by deprecated users.
See also: @code{DeleteNonOwnerFiles}, @code{DeleteNonUserFiles}.

@example
  SpoolDirectories = ( /var/spool/cron/crontabs /var/spool/cron/atjobs )
@end example

@c .....................................................
@c SUBSECTION
@c .....................................................

@node suninstallcommand, suspiciousnames, spooldirectories, control
@subsection SUNInstallCommand

Sets the command used to install packages that need to be installed
under the SUN package manager.

@smallexample
SUNInstallCommand = ( "/usr/bin/pkgmgr %s" )
@end smallexample

By default, this variable is not set, meaning that any packages with
action=install will NOT be installed if installation is required.  Note
the quotes around the string, and the @code{%s} is replaced with the name
of the package to be installed.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node suspiciousnames, sysadm, suninstallcommand, control
@subsection suspiciousnames
@cindex suspiciousnames
@vindex SuspiciousNames

@example
  SuspiciousNames = ( .mo lrk3 )
@end example

Filenames in this list are treated as suspicious and generate a warning
as cfengine scans directories. This might be used to detect hacked systems
or concealed programs. Checks are only made in directories which cfengine
scans in connection with a command such as files, tidy or copy.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node sysadm, Syslog, suspiciousnames, control
@subsection sysadm
@cindex sysadm
@vindex sysadm

@example
   sysadm = ( @var{mail address} )
@end example

The mail address of your system administrator should be placed here.
This is used in two instances.  If cfengine is invoked with the option
@code{-a}, then it simply prints out this value.  This is a handy
feature for making scripts.

The administrators mail address is also written into the personal log
files which cfengine creates for each user after tidying files, so you
should make this an address which users can mail if they have troubles.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Syslog, SyslogFacility, sysadm, control
@subsection Syslog

@w{}
@smallexample

  Syslog = ( @var{on/}@b{off} )

@end smallexample

This variable activates syslog logging of cfengine output at
the `inform' level.

To set this output level one writes:

@smallexample

 @var{classes}::

   Syslog = ( on )

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node SyslogFacility, timezone, Syslog, control
@subsection SyslogFacility

@w{}
@smallexample

  SyslogFacility = ( @var{facility} )

@end smallexample

This variable alters the syslog facility level.
e.g.

@smallexample

   SyslogFacility = ( LOG_LOCAL1 )

@end smallexample

Valid arguments are 

@smallexample
LOG_USER
LOG_DAEMON
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node timezone, TimeOut, SyslogFacility, control
@subsection timezone

@example
   timezone = ( @var{3-character timezone} )
@end example

The timezone variable is a list of character strings which define your local
timezone.  Normally you will only need a single timezone, but sometimes
there are several aliases for a given timezone e.g. MET and CET are synonymous.
Currently only the first three characters of this string are
checked against the timezone which cfengine manages to glean from the
system.  If a mismatch is detected a warning message is printed.
cfengine does not attempt to configure the timezone.  This feature works
only as a reminder, since the timezone should really be set once and for
all at the time the system is installed.  On some systems you can set
the timezone by editing a file, a procedure which you can automate with
cfengine @xref{editfiles}.

The value of the @code{timezone} can be accessed by variable substitution
in the usual way. It expands to the first item in your list.

@smallexample
shellcommands:

       "echo $@{timezone@} | mail $@{sysadm@}"

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................

@node TimeOut, Verbose, timezone, control
@subsection TimeOut

@w{}
@smallexample

  TimeOut = ( 10 )

@end smallexample

The default timeout for network connections is 10 seconds. This
is too short on some routed networks. It is not permitted to set
this variable smaller than 3 seconds or larger than 60 seconds.
A timeout is generated by an `alarm' interrupt within an executing
agent. This is constrasted with ExpireAfter, in which a second agent
is required to interrupt the activity.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Verbose, Warnings, TimeOut, control
@subsection Verbose

@w{}
@smallexample

  Verbose = ( @var{on/}@b{off} )

@end smallexample

This variable switches on the output level whereby cfengine
reports everything it does during a run in great detail. Normally only
urgent messages or clear errors are printed, @xref{Inform}.
This option is almost equivalent to using the @kbd{--verbose} of @kbd{-v}
command-line options. The only difference is that system environment reporting
information, which is printed prior to parsing, is not shown.
To set this output level on selected hosts one writes:

@smallexample

 @var{classes}::

   Verbose = ( on )

@end smallexample

For related more limited output, @xref{Inform}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Warnings, warnnonuserfiles, Verbose, control
@subsection Warnings

@w{}
@smallexample

  Warnings = ( @var{on/}@b{off} )

@end smallexample

This variable switches on the parser-output level whereby cfengine
reports non-fatal warnings.  This is equivalent to setting the command
line switch @kbd{--no-warn}, or @kbd{-w}.  To set this output level on
selected hosts one writes:

@smallexample

 @var{classes}::

   Warnings = ( on )

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................

@node warnnonuserfiles, warnnonownerfiles, Warnings, control
@subsection WarnNonUserFiles

If this parameter is set to true, cfengine will warn about files in
spool directories which do not have a name belonging to a known user id.

See also @code{DeleteNonUserFiles}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node warnnonownerfiles, warnnonusermail, warnnonuserfiles, control
@subsection WarnNonOwnerFiles

If this parameter is set to true, cfengine will warn about files on
mailservers whose names do not correspond to a known user name, but
might be owned by a known user.

@smallexample

SpoolDirectories = ( /var/spool/cron/crontabs )

WarnNonOwnerFiles = ( true )

@end smallexample

See also @code{DeleteNonOwnerFiles}. This generalizes and succeeds @code{DeleteNonOwnerMail}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node warnnonusermail, warnnonownermail, warnnonownerfiles, control
@subsection WarnNonUserMail

If this parameter is set to true, cfengine will warn about mail files on
mailservers which do not have a name belonging to a known user id. This
does not include lock files.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node warnnonownermail,  , warnnonusermail, control
@subsection WarnNonOwnerMail

If this parameter is set to true, cfengine will warn about files on
mailservers whose names do not correspond to a known user name, but
might be owned by a known user.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node classes, copy, control, Cfagent reference
@section classes
@cindex @code{classes}
@cindex Defining classes
@cindex groups

The @code{classes} keyword is an alias for @code{groups} as of
version 1.4.0 of cfengine.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node copy, defaultroute, classes, Cfagent reference
@section copy
@cindex copy
@cindex Copying files
@cindex File images (copy)

Cfengine copies files between locally mounted filesystems and via the
network from registered servers.  The copy algorithm avoids
race-conditions which can occur due to network and system latencies by
copying first to a file called @file{@var{file}.cfnew} on the local
filesystem, and then renaming this quickly into place.  The aim of this
roundabout procedure is to avoid situations where the direct rewriting
of a file is interrupted midway, leaving a partially written file to be
read by other processes.  Cfengine attempts to preserve hard links to
non-directory file-objects, but see the caution below.
@cindex @file{.cfnew} files

@emph{Caution should be exercised in copying files which change rapidly in size.
This can lead to file corruption, if the size changes during copying. Cfengine
attempts to prevent this during remote copies.}

The syntax summary is:

@cartouche

@w{}
@smallexample

copy:

   @var{class}::

      @var{master-file} 
                        dest=@var{destination-file} 

                        mode=@var{mode}
                        owner=@var{owner} 
                        group=@var{group} 
                        action=@var{warn/silent/fix}
                        backup=@b{true}@var{/false/timestamp}
                        repository=@var{backup directory}
                        stealth=@var{true/on/@b{false/off}}
                        checkroot=@var{true/on/@b{false/off}}
                        timestamps=@b{preserve/keep}
                        symlink=@var{pattern}

                        include=@var{pattern}
                        exclude=@var{pattern} 
                        ignore=@var{pattern}
                        filter=@var{filteralias}
                        xdev=@var{true/on}/@b{false/off}

                        recurse=@var{number/inf/}@var{0}
                        type=@b{ctime}@var{/mtime/checksum/sum/byte/binary/any}
                        linktype=@b{absolute/symbolic}@var{/relative/hard/none/copy}
                        typecheck=@b{true/on}/@var{false/off}
                        define=@var{class-list}(,:.)
                        elsedefine=@var{class-list}(,:.)

                        force=@var{true/on}/@b{false/off}
                        forcedirs=@var{true/on}/@b{false/off}
                        forceipv4=@var{true/on}/@b{false/off}
                        size=@var{size limits}
                        server=@var{server-host}
                        failover=@var{classes}

                        trustkey=@var{true}/@b{false}
                        secure=[deprecated]
                        encrypt=@var{true}/@b{false}
                        verify=@var{true}/@b{false}
                        oldserver=@var{true}/@b{false}

                        purge=@var{true/}@b{false}

                        syslog=@var{true/on}/@var{false/off}
                        inform=@var{true/on}/@var{false/off}
                        audit=@var{true/false}

                        findertype=@var{MacOSX finder type}

@end smallexample
@end cartouche

@noindent
Note that the @code{$(this)} contains the name of the server
used. This variable may be used in the source and destination strings
in order to tailor the filename when downloading from multiple sources
(see below).

@table @code

@anchor{dest}
@item dest
The destination file is the only obligatory item. This must be the name
of an object which matches the type of the master object i.e. if the
master is a plain file, the destination must also be the explicit name
of a plain file. An implicit `copy file to directory' syntax is not
allowed.  Symbolic links are copied as symbolic links, plain files are
copied as plain files and special files are copied as special files.
The @code{recurse} option is required to copy the contents of subdirectories.

If the destination file name is of the form
@file{filename/..namedfork/rsrc}, then it is assumed that you are
copying the resource fork of a file to an HFS+ file system on OS X
Jaguar. In the absence of the destination file being in this form (just
dest=filename), cfengine will assume that you are working with the data
fork of the file. See @ref{dest}.

For a resource fork copy to properly work, the data fork must
have already been copied. Ie the OS will not allow you to copy the
resource fork for a file that does not exist. And, copying a data fork
after the resource fork will overwrite the resource fork. So, order is
important.  Copy the data fork, first. Then, copy the resource fork.

To split the data and resource forks of a file into two parts,
open up a terminal.  The following commands will copy MyFile 's data and
resource forks into two separate files which can then be recombined by
cfengine:

@smallexample
	cp MyFile MyFile-datafork
	cp MyFile/..namedfork/rsrc MyFile-rsrcfork
@end smallexample

@item mode, owner, group
The file mode, owner
and group of the images are specified as in the @code{files} function
@xref{files}. 


@anchor{copyaction}
@item action
The action may take the values @code{warn}, @code{silent} or
@code{fix}. The default action is @code{fix}, i.e.  copy files. If
@code{warn} is specified, only a warning is issued about files which
require updating. If @code{silent} is given, then cfengine will copy
the files but not report the fact.

@anchor{force}
@item force
If set to `true', this option causes cfengine to copy files regardless
of whether it is up to date.

@anchor{forceipv4}
@item forceipv4
If you are working on an ipv6 enabled pair of hosts, cfengine will
normally select ipv6 for communication between them. If you wish
to force the use of ipv4 for some reason, set this option to true.

@anchor{forcedirs}
@item forcedirs
If set to `true', this option causes files or links which block the
creation of directories, during recursive copying, to be moved
aside forcably. A single non-supressable warning is given when this
occurs; the file is moved to filename@file{.cf-moved}.

@anchor{copybackup}
@item backup
If the @code{backup} option is set to ``false'', cfengine
will not make a backup copy of the file before copying. The default value is ``true''.
If the option ``timestamp'' is chosen, a unique timestamp will be appended
to the saved filename.
@cindex Backup of files in copy
@vindex backup=
@cindex Switching off backup in copy

@anchor{copyrepository}
@item repository
This allows a local override of the @code{Repository} variable, on an item
by item basis. If set to ``off'' or ``none'' it cancels the value of a global repository.

Copy makes a literal image of the master file at the destination,
checking whether the master is newer than the image. If the image needs
updating it is copied. Existing files are saved by appending
@code{.cfsaved} to the filename.

@anchor{stealth}
@item stealth
If set to `on' causes cfengine to preserve atime and mtime
on the source files during @emph{local} 
file copies. File times cannot be preserved on
remote copies. This option should normally only be used
together with a checksum copy, since preserving atime and mtime
implies changing ctime which will force continual copying.
This is a weakness in the Unix file system. Ctime cannot be
preserved. Before version 1.5.0, there was a typo which
made this option active on many file copies.
@mbindex ctime copy doesn't always copy files
@mbindex copy doesn't always copy files

@anchor{checkroot}
@item checkroot
Default value @code{false}, this option causes cfengine to check the
permissions of the root directory during recursive directory
copies. If not true, cfengine sets its own permissions on the root.

@anchor{timestamps}
@item timestamps
If this is set to `preserve' or `keep', the times of the source
files are inherited by the destination files during copying. This is
like the `p' option of the @code{tar} command.
@cindex Preserving file times in copy

@anchor{recurse}
@item recurse
Specifies the depth of recursion when copying whole file-trees
recursively. The value may be a number or the keyword @code{inf}.
Cfengine crosses device boundaries or mounted filesystems when
descending recursively through file trees. To prevent
this it is simplest to specify a maximum level of recursion.
@cindex Device boundaries
@cindex Mounted filesystems

@anchor{symlink}
@item symlink
This option may be repeated a number of times to specify the
names of files, or wildcards which match files which are to
be symbolically linked instead of copied. A global list of
patterns can also be defined in the control section of the program
@xref{linkcopies}.

@anchor{copyignore}
@item ignore
This works like the global ignore directive but here you may
provide a private list of ignorable directories and files.
Unlike include, exclude this affects the way cfengine parses
directory trees.

@anchor{copyinclude}
@item include
This option may be repeated a number of times to specify the names of
files, or wildcards which match files which are to be included in a copy
operation. Specifying one of these automatically excludes everything
else except further include patterns.  A global list of patterns can
also be defined in the control section of the program.

@cindex Purge, excluding files
If the @code{purge} option is used in copying, then the @code{ignore} option
has the effect of the excluding files from the purge, i.e. @code{ignore} means
`keep' the named files.

@anchor{copyexclude}
@item exclude
This option may be repeated a number of times to specify the
names of files, or wildcards which match files which are to
be excluded from a copy operation. A global list of
patterns can also be defined in the control section of the program
`excludes' override `includes'.
@xref{excludelinks}.

@anchor{copyxdev}
@item xdev
Prevents cfengine from descending into file systems that are not on the
same device as the root of the rescurion path.
@cindex xdev

@anchor{copytype}
@item type
Normally cfengine uses the ctime date-stamps on files to determine
whether a file needs to be copied: a file is only copied if the master
is newer than the copy or if the copy doesn't exist. If the type is set
to @samp{checksum} or @samp{sum}, then a secure MD5 checksum is used to
determine whether the source and destination files are identical. If
@samp{byte} or @samp{binary} is specified, a byte by byte comparison is
initiated.  An @samp{mtime} comparison does not take into account
changes of file permissions, only modifications to the contents of the
files.

@anchor{findertype}
@item findertype
	Sets the four letter file type code in an HFS+ file system on Mac OS X
	Jaguar. For example, the four letter code APPL indicates the file is an
	Application (and will be executed when double-clicked). The four letter
	code TEXT indicates the file is a text file and will be opened by the
	default text editor.

	If the file also has an extension (for example @code{.txt}),
then if setting the finder type code, you should make sure your finder
type code does not conflict with the file extension.

	Files both without extensions and finder type codes are mostly useless
	to OS X, so be sure to do one or the other!

	Also note that finder type codes should not be applied to the resource
	forks of files.

@anchor{server}
@item server
If you want to copy a file remotely from a server, you specify the
name of the server here. This must be the name of a host which is
running the @code{cfservd} daemon, and you must make sure that you
have defined the variable @code{domain} in the control section
of the @file{cfagent.conf} file. If you don't define a domain
you will probably receive an error of the form `cfengine: Hey! cannot
stat file'. If the server name is `localhost', cfengine will perform a local
copy, without using a connection to cfservd.
@mbindex Hey! Cannot stat file error
@mbindex Remote copy problems, can't stat
@mbindex locahost in copy

@anchor{failover}
@item failover
If a file copy fails due to an error, the classes in this assignment
will become active, allowing failover rules to become active.
@cindex failover

@anchor{oldserver}
@item oldserver
If this is true, cfengine uses the old protocol specification for
temporary compatibility with early version 2 alphas.

@anchor{trustkey}
@item trustkey
This option defaults to 'no' or 'false'. If set to true, cfagent will
accept a public key from a server whose public key is presently unknown
to the agent, on trust. This option should be used to bootstrap public
key transfer between hosts. Once a public key has been accepted, it will
not be replaced automatically. Dated public keys must be removed
by hand.
@cindex Public keys
@cindex Trusted hosts

@anchor{encrypt}
@item encrypt
Has an effect only when used in conjuction with copy from a remote file
server.  This causes cfengine to use encryption and one-time keys on
transferred data.  (This requires RSA keys to be installed on both client
and server hosts, and provides strong authentication and encryption,
using random session keys.) The preferred algorithm is Blowfish, with a
128 bit key. Generally speaking the only case in which this function
makes sense is in transferring shadow password files.  Encrypting the
transfer of system binaries makes little sense. Note: the
encryption keys required to get files from cfservd are those for the
user under which cfservd is running (normally root).

@anchor{verify}
@item verify
If verify is true, cfagent attempts to verify the integrity of a remote
file transfer before the new file is installed. This takes time, since
an MD5 computation and transaction must take place.

@anchor{size}
@item size
With this option you can specify that a file is only to be copied if the
source file meets a size critereon. This could be used to avoid
installing a corrupted file (the copying of an empty password file, for
instance). Sizes are in bytes by default, but may also be quoted in
kilobytes or megabytes using the notation:

@smallexample

@var{number}bytes
@var{number}kbytes
@var{number}mbytes

@end smallexample
@noindent
Only the first characters of these strings are significant, so they may
be written however is convenient: e.g. @kbd{14kB}, @kbd{14k},
@kbd{14kilobytes} etc.
 Examples are:

@smallexample

   size=<400  # copy if file size is < 400 bytes
   size=400   # copy if file size is equal to 400 bytes
   size=>400  # copy if file size > 400 bytes

@end smallexample
@noindent

@anchor{linktype}
@item linktype
This option determines the type of link used to make links. This only
applies if the file is linked rather than copied because it matches
a pattern set by @code{symlink}. The default type is a direct symbolic
link. The values @samp{relative} or @samp{absolute} may be used, but
hard links may not be created in place of copied files, since hard links
must normally reside on the same filesystem as their files, and it
is assumed that most links will be between filesystems. If this value
is set to @code{copy} or @code{none}, symbolic links will be replaced
by actual copies of the files they point to. Note that for directories,
this option is ignored.

@anchor{typecheck}
@item typecheck
Controls whether cfengine allows files of one type to overwrite files of
another type, i.e. switches on/off errors if source and existing
destination files do not match in type, e.g. if a file would overwrite a
directory or link. The default is on for safety reasons.

@anchor{copydefine}
@item define
This option is followed by a list of classes which are to be `switched on'
if and only if the named file was copied.  In multiple (recursive) copy
operations the classes become defined if any of the files in the file
tree were copied. This feature is useful for switching on other actions
which are to be performed after the installation of key files (e.g.
package installation scripts etc).

@anchor{purge}
@item purge
If this option is set to true, cfengine will remove files in the
destination directory which are not also in the source directory.  This
allows exact images of filesystems to be mantained. Note that if the
copy command has includes or excludes or ignored files, cfengine will
purge only those files on the client machine which are also on the
server. Included files are not purged. 
This means that some files (such as system specific work files)
can be excluded from copies without them being destroyed.
@vindex purge=
@cindex Copy, exact filetree images
@cindex File tree images
@cindex Tree copying, exact
Note that purging is disallowed if contact with a remote server fails.
This means that local files will not be destroyed by a denial of service
attack. @emph{You should not use this option to synchronize NFS mounted
file systems. If the NFS server goes down, cfengine cannot then tell the
difference between a valid empty directory and a missing NFS file system.
If you use purge, use a remote copy also.}
If we specify purge, then the following options will also be set and
cannot be altered: @code{forcedirs=true}, @code{typecheck=false}, since
other defaults could be very destructive.

@end table

@menu
* copy example::                
* hard links in copy::          
* Too many open files::         
@end menu

@node copy example, hard links in copy, copy, copy
@subsection copy example

Example:

@smallexample

copy:

      /local/etc/aliases dest=/etc/aliases m=644 o=root g=other
      /local/backup-etc  dest=/etc

   solaris::

      /local/etc/nsswitch.conf dest=/etc/nsswitch.conf

@end smallexample

@noindent
In the first example, a global aliases file is copied from the master
site file @file{/local/etc/aliases} to @file{/etc/aliases}, setting the
owner and protection as specified. The file gets installed if
@file{/etc/aliases} doesn't exist and updated if @file{/local/etc/aliases}
is newer than @file{/etc/aliases}. In the second example, @file{backup-etc}
is a directory containing master configuration files (for instance, @file{services},
@file{aliases}, @file{passwd}...). Each of the files in @file{backup-etc}
is installed or updated under @file{/etc}. Finally, a global
@file{nsswitch.conf} file is kept up to date for Solaris systems.

The @code{home} directive can be used as a destination, in which
case cfengine will copy files to every user on the system. This is
handy for distributing setup files and keeping them updated:

@smallexample

copy:

   /local/masterfiles/.cshrc  dest=home/.cshrc mode=0600

@end smallexample

@noindent
You can force the copying of files, regardless of the date stamps
by setting the option @code{force=true} or @code{force=on}. The default
is @code{force=false} or @code{force=off}.
@cindex Force copying
@vindex force=

@menu
* hard links in copy::          
* Too many open files::         
@end menu

@node hard links in copy, Too many open files, copy example, copy
@subsection Hard links in copying

Hard links are not like symbolic links, they are not merely pointers to
other files, but alternative names for the same file. The name of every
file is a hard link, the first so to speak. You can add additional names
which @emph{really are} the file, they are not just pointers. For the
technically minded, they are not separate inodes, they are additional
directory references to the same inode.  When you perform a copy
operation on multiple files, cfengine attempts to preserve hard links
but this is a difficult task. 

Because a hard link just looks like an ordinary file (it cannot be
distingiushed from the original, the way a symbolic link can)
there is a danger that any copy operation will copy two hard links to
the same file as two separate copies of the same file. The difference
is that changes a hard-linked file propagate to the links, whereas
two copies of a file are completely independent thereafter.
In order to faithfully reproduce all hardlinks to all files, cfengine
needs to examine every file on the same filesystem and check whether
they have the same inode-number. This would be an enourmous overhead, so it
is not done. Instead what happens is that cfengine keeps track of only
the files which it is asked to examine, for each atomic copy-command,
and makes a note of any repeated inodes within this restricted set.
It does not try to go off, wandering around file systems looking to
other files which might be hardlinks.

To summarize, cfengine preserves hardlinks during copying, only
within the scope of the present search. No backups are made of
hard links, only of the first link or name of the file is backed
up. This is a necessary precaution to avoid dangling references
in the inode table. As a general rule, hard links are to be avoided
because they are difficult to keep track of.

@node Too many open files,  , hard links in copy, copy
@subsection Too many open files

@cindex Too many open files error
@mbindex Too many open files error
In long recursive copies, where you descend into many levels of diretories,
you can quickly run out of file descriptors. The number of file descriptors
is a resource which you can often set in the shell. It is a good idea
to set this limit to a large number on a host which will be copying
a lot of files. For instance, in the C shell you would write,

@smallexample

limit descriptors 1024

@end smallexample

@noindent Most systems should have adequate defaults for this parameter, but
on some systems it appears to be set to a low value such as 64, which is
not sufficient for large recursive tree searches.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node defaultroute, disks, copy, Cfagent reference
@section defaultroute

Dynamical routing is not configurable in cfengine, but for machines with
static routing tables it is useful to check that a default route is
configured to point to the nearest gateway or router.  The syntax for
this statement is simply:

@smallexample

defaultroute:

   @var{class}::

      my_gateway

@end smallexample 

@noindent
For example:

@smallexample

defaultroute:

  most::

     129.240.22.1

  rest::
 
     small_gw

  no_default_route::

     192.168.1.1

@end smallexample 

@noindent
Gateways and routers usually have internet address @code{aaa.bbb.ccc.1}
--- i.e.  the first address on the subnet.  You may use the numerical
form or a hostname for the gateway.

The class @code{no_default_route} is defined if the current host does not have a currently
defined default route, but specifies one in its configuration.
@cindex no_default_route class

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node disks, directories, defaultroute, Cfagent reference
@section disks

This is a synonyn for @code{required}, @xref{required}.
@cindex disks actions
This action tests for the existence of a file or filesystem.  It should
be called after all NFS filesystems have been mounted.  You may use the
special variable @code{$(binserver)} here.

@cartouche

@w{}
@smallexample

  disks:

    /@var{filesystem} freespace=@var{size-limit} define=@var{class-list}(,:.) 

     inform=@var{true} 
     log=@var{true} 
     audit=@var{true/false}

     scanarrivals=@var{true} 
     force=@var{true}
     
     ifelapsed=@var{mins} 
     expireafter=@var{mins}

@end smallexample
@end cartouche

Files or filesystems which you consider to be essential to the operation
of the system can be declared as `required'.  Cfengine will warn
if such files are not found, or if they look funny.

Suppose you mount your filesystem @code{/usr/local} via NFS from some
binary server.  You might want to check that this filesystem is not
empty! This might occur if the filesystem was actually @emph{not}
mounted as expected, but failed for some reason.  It is therefore not
enough to check whether the directory @code{/usr/local} exists, one must
also check whether it contains anything sensible.

Cfengine uses two variables: @code{sensiblesize} and
@code{sensiblecount} to figure out whether a file or filesystem is
sensible or not.  You can change the default values of these variables
(which are 1000 and 2 respectively) in the @code{control} section.
@xref{control}.

If a file is smaller than @code{sensiblesize} or does not exist, it
fails the `required' test.  If a directory does not exist, or contains
fewer than @code{sensiblecount} files, then it also fails the test and a
warning is issued.

@smallexample

disks:

   any::
      
      /$(site)/$(binserver)/local

@end smallexample

If you set the @code{freespace} variable to a value and set @code{inform=true},
cfagent issues warnings when free disk space falls below this threshold.
Any define-classes also become defined in this instance.
(the default units are kilobytes,
but you may specify bytes or megabytes), e.g.
@vindex freespace=
@cindex freespace=
@cindex Warning about full disks
@cindex Full disk warnings


@w{}
@smallexample

required:

  /site/host/home1 freespace=50mb define=dotidy
  /site/host/home2 freespace=10% define=dotidy

@end smallexample
@cindex Percentage disk space

@noindent
then cfengine will warn when the filesystem concerned has less than this
amount of free space. By adding a @code{define} tag, you can switch on
any number of classes if this happens. This allows you to activate special
measures for dealing with a filesystem which is in danger of becoming
full.


If the option @code{force=true} is used, cfengine will parse filesystems
even on NFS mounted filesystems. Normally it does not make sense to
check filesystems that are not native to the local host, but occasionally
ne would like to force such a check in order to set a class, based on the
result, for instance.
@vindex force=
@cindex NFS filesystems and disk checking
@cindex Setting classes based on non-local disks

@vindex scanarrivals=
@cindex scanarrivals=

If the @code{scanarrivals} option is set, the agent will recursively descend
through the file system building a database of file modification times. This
data is used for research purposes and will eventually be used to trigger
classes that determine optimal times for backup of filesystem.

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node directories, disable, disks, Cfagent reference
@section directories

@cindex Directories, making
@cindex Paths, making
@cindex Making directories
@cindex Making paths

Directories declarations consist of a number of directories to be
created.  Directories and files may also be checked and created using
the @code{touch} option in the @code{files} actions.  @xref{files}.

The form of a declaration is:

@cartouche

@w{}
@smallexample

  directories:

     @var{classes}::

         /@var{directory} 
                         mode=@var{mode} 
                         owner=@var{uid}
                         group=@var{gid}
                         rxdirs=@var{true/on}/@var{false/off}

                         define=@var{classlist}
                         elsedefine=@var{classlist}
                         syslog=@var{true/on}/@var{false/off}
                         inform=@var{true/on}/@var{false/off}
                         audit=@var{true/on}/@var{false/off}

                         ifelapsed=@var{mins} 
                         expireafter=@var{mins}
@end smallexample
@end cartouche

@noindent
For example

@smallexample

directories:

  @var{class}::

     /usr/local/bin  mode=755 owner=root group=wheel

@end smallexample 

@noindent
The form of the command is similar to that of @code{files} but this
command is only used to create new directories.  Valid options are
@code{mode}, @code{owner}, @code{group} and @code{rxdirs}; these are described under
@code{files} @xref{files}. This interface is only for convenience.
It is strictly a part of the `files' functionality and is performed
together with other `files' actions at run time.

The creation of a path will fail if one of the links in the path is a
plain file or device node.  A list of classes may optionally be defined
here if a directory is created.

If the @code{owner} value is set to the literal "LastNode", then the
owner will be exchanged for the last node of the path. This allows the
creation of home directories owned by users.

@cindex Home directories, creating
@cindex @code{LastNode} literal
@smallexample

control:

  homedirs = ( mark:simen:luke:aeleen )

directories:

  /home/$(listcontent) owner=LastNode


@end smallexample

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node disable, editfiles, directories, Cfagent reference
@section disable
@cindex Disabling files
@cindex Renaming files
@vindex disable

Disabling a file means renaming it so that it becomes harmless.  This
feature is useful if you want to prevent certain dangerous files from
being around, but you don't want to delete them--- a deleted file cannot
be examined later.  The syntax is

@cartouche

@w{}
@smallexample

 disable:

   @var{class}::

      /@var{filename}
                      dest=@var{filename}

                      type=@var{plain/file/link/links}
                      rotate=@var{empty/truncate/numerical-value}
                      size=@var{numerical-value}
                      define=@var{classlist}
                      syslog=@var{true/on}/@b{false/off}
                      inform=@var{true/on}/@b{false/off}
                      audit=@var{true/on}/@var{false/off}

                      repository=@var{destination directory}
                      action=@b{disable}/@var{warn}

                      ifelapsed=@var{mins} 
                      expireafter=@var{mins}

@end smallexample
@end cartouche

@noindent
If a destination filename is specified, cfagent renames the source file
to the destination, where possible (renaming across filesystems is not
allowed).  If no destination is given, cfagent renames a given file by
appending the name of the file with the suffix @file{.cfdisabled}.  Note
that directories are only renamed if they have a specific destination
specified.

A typical example of a file you would probably want to disable would be
the @code{/etc/hosts.equiv} file which is often found with the @samp{+}
symbol written in it, opening the system concerned to the entire NIS
universe without password protection!
@cindex @file{/etc/hosts.equiv}
@cindex @code{.cfdisabled}
Here is an example:

@smallexample

disable:

      /etc/hosts.equiv
      /etc/nologin
      /usr/lib/sendmail.fc

   sun4::

      /var/spool/cron/at.allow

@end smallexample 

@noindent
Hint: The last example disables a file which restricts access to the
@code{at} utility.  Such a command could be followed by a file action,
@xref{files},

@w{}
@smallexample
files:

   some::

      /var/spool/cron/at.allow =0644 N owner=root group=wheel touch

@end smallexample 

@noindent
which would create an empty security file @file{at.allow}.
See also your system manual pages for the @code{at} command if you don't
understand why this could be useful.

Disabling a link deletes the link. If you wish you may use the
optional syntax

@smallexample

disable:

    /directory/name type=file

@end smallexample

@noindent
to specify that a file object should only be disabled if it is a plain
file. The optional element @code{type=} can take the values
@code{plain}, @code{file}, @code{link} or @code{links}. If one of
these is specified, cfengine checks the type and only disables
the object if there is a match. This allows you to disable a file
and replace it by a link to another file for instance.
@cindex Replacing file by link
@vindex type=
@cindex Disabling file types

NOTE that if you regularly disable a file which then gets recreated by
some process, the disabled file @file{@var{filename}.cfdisabled} will
be overwritten each time cfengine disables the file and therefore the
contents of the original are lost each time. The @code{rotate} facility
was created for just this contingency.
@cindex Truncating log files
@cindex Controlling the size of log files
@cindex Log files, controlling the size of
@cindex Rotating log files

The disable feature can be used to control the size of system log files,
such as @file{/var/adm/messages} using a further option @code{rotate}.
@vindex rotate=
@vindex empty
@vindex truncate
If the value rotate is set to 4, say, 

@smallexample

 disable:

    @var{filename}  rotate=4

@end smallexample

@noindent
then cfengine renames
the file concerned by appending `.1' to it and a new, empty file is
created in its place with the same owner and permissions. The next time
disable is executed `.1' is renamed to `.2' and the file
is renamed `.1' and a new empty file is created with the same
permissions. Cfengine continues to rotate the files like this
keeping a maximum of four files. This is similar to the behaviour
of syslog.

If you simply want to empty the contents of a log file, without
retaining a copy then you can use @code{rotate=empty} or
@code{rotate=truncate}. For instance,
to keep control of your World Wide Web server logs:

@smallexample
disable:

   Sunday|Wednesday::

       /usr/local/httpd/logs/access_log  rotate=empty
@end smallexample

@noindent
This keeps a running log which is emptied each Sunday and Wednesday.
@cindex WWW server logs

The @code{size=} option in disable allows you to carry out a disable
operation only if the size of the file is less than, equal to or greater
than some specified size. Sizes are in bytes by default, but
may also be quoted in kilobytes or megabytes using the notation:

@smallexample

@var{number}bytes
@var{number}kbytes
@var{number}mbytes

@end smallexample
@noindent
Only the first characters of these strings are significant, so they may
be written however is convenient: e.g. @kbd{14kB}, @kbd{14k},
@kbd{14kilobytes} etc.
 Examples are:

@smallexample

   size=<400  # disable if file size is < 400 bytes
   size=400   # disable if file size is equal to 400 bytes
   size=>400  # disable if file size > 400 bytes

@end smallexample
@noindent
This options works with @code{rotate} or normal disabling; it is just
an extra condition which must be satisfied.
@cindex size field in disable

If a disable command results in action being taken by cfengine, an optional
list of classes becomes can be switched on with the aid of a statement
@code{define=@var{classlist}} in order to trigger knock-on actions.

The @code{repository} declaration allows a local override of the
@code{Repository} variable, on an item by item basis. If set to ``off'' or
``none'' it cancels the value of a global repository and leaves the disabled
file in the same directory.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node editfiles, Editfiles on Binary Files, disable, Cfagent reference
@section editfiles

Performs ascii (line-based) editing on text-files or limited binary
editing of files.  If editing a file which has hard links to it, be
aware that editing the file will destroy the hard link references. This
is also the case with shell commands. You should avoid hard links
whenever possible.
@cindex awk, editing
@cindex sed, editing
The form of an editing command is
@code{editfiles} can also search directories recursively through directories
and edit all files matching a pattern, using @code{Include}, @code{Exclude}, and
@code{Ignore} (see Recursive File Sweeps in the tutorial).

@cartouche

@w{}
@smallexample

editfiles:

   @var{class}::

      @{ @var{file-to-be-edited}

      @var{action} "@var{quoted-string...}"
      @}

      @{ @var{directory-to-be-edited}

      Recurse "inf"          # iterated over all files
      Filter  "filteralias"
      Include ".cshrc"
      Ignore  "bin"
      Ignore  ".netscape"
      @var{action} "@var{quoted-string...}"
      @}

@end smallexample 
@end cartouche

@noindent
Here are some examples:

@smallexample
editfiles:

   sun4::

      @{ /etc/netmasks

      DeleteLinesContaining "255.255.254.0"
      AppendIfNoSuchLine "128.39  255.255.255.0"
      @}

   PrintServers::
      @{ /etc/hosts.lpd

      AppendIfNoSuchLine "tor"
      AppendIfNoSuchLine "odin"
      AppendIfNoSuchLine "borg"
      @}

@end smallexample 

@noindent
The first of these affects the file @file{/etc/netmasks} on all SunOS 4
systems, deleting any lines containing the string ``255.255.254.0'' and
Appending a single line to the file containing ``128.39 255.255.255.0''
if none exists already.  The second affects only hosts in the class
`PrintServers' and adds the names of three hosts: tor, odin and borg to
the file @file{/etc/hosts.lpd} which specifies that they are allowed to
connect to the printer services on any host in the class `PrintServers'.

@cindex Quoted strings
@cindex Single quotes
@cindex Double quotes
@noindent
Note that single or double quotes may be used to enclose strings
in cfengine. If you use single quotes, your strings may contain
double quotes and vice-versa. Otherwise a double quoted string
may not currently contain double quotes and likewise for
single quoted strings.

As of version 2.0.6 quoted strings may contain escaped quotes
using @code{\"}.

As of version 1.3.0, you can use the @samp{home} directive in
edit filenames, enabling you to edit files for every user
on the system, provided they exist. For example, to edit
every user's login files, you would write

@smallexample

  @{ home/.cshrc

   AppendIfNoSuchLine "setenv PRINTER default-printer"
   AppendIfNoSuchLine "set path = ( $path /new/directory )"
  @}

@end smallexample

@noindent
If a user does not possess the named file, cfengine just skips
that user. A new file is not created.

@noindent
The meanings of the file-editing actions should be self-explanatory.
Commands containing the word 'comment' are used to `comment out' certain
lines in a file rather than deleting them.  @code{Hash} implies a shell
comment of the type

@smallexample
# comment
@end smallexample 

@noindent
@code{Slash} implies a comment of the C++ type:

@w{}
@smallexample
// comment
@end smallexample 

@noindent
@code{Percent} implies a comment of the type:

@w{}
@smallexample
% comment
@end smallexample

More general comment types may be defined using the
@code{SetCommentStart}, @code{SetCommentEnd} and
@code{CommentLinesMatching}, @code{CommentLinesStarting}
functions.

A special group of editing commands is based on the POSIX Regular
Expression package. These use regular expressions to search line by
line through text and perform various editing functions. Searches are of two
different types: ``LineMatching'' and ``LineContaining''. In the first case
the regular expression must match the entire line exactly; in the latter,
a substring is searched for in the file.

Some of these commands are based on the concept of a file pointer. The
pointer starts at line one of the file and can be reset by 'locating' a
certain line, or by using the reset-pointer commands. The current
position of the pointer is used by commands such as @code{InsertLine} to
allow a flexible way of editing the middle of files.

A simple decision mechanism is incorporated to allow certain editing
actions to be excluded. For instance, to insert a number of lines
in a file once only, you could write:

@smallexample

   @{ @var{file}

    LocateLineMatching "@var{insert point...}"
    IncrementPointer   "1"

    BeginGroupIfNoMatch "# cfengine - 2/Jan/95"
      IncrementPointer "-1"
      InsertLine "# cfengine - 2/Jan/95"
      InsertLine "/local/bin/start-xdm"
      DefineInGroup "AddedXDM"
    EndGroup
   @}

@end smallexample

@noindent
Since the first inserted line matches the predicate on subsequent calls,
the grouped lines will only be carried out once. When the grouped
lines are run, the @samp{AddedXDM} class will be activated for use by
a later part of the script.




The full list of editing actions is given below in alphabetical order.
Note that some commands refer to regular expressions and some refer to
'literal strings' (i.e. any string which is not a regular
expression). Variable substitution is performed on all strings.  Be
aware that symbols such as @samp{.}, @samp{*} and so on are
meta-characters in regular expressions and a backslash must be used to
make them literal.  The regular expression matching functions are 
POSIX extended regular expressions.
@xref{Regular expressions,Regular expressions,Regular
expressions,cfengine-Tutorial}. 


@cartouche
@b{Editfile caution.}
It is suggested that you use these editing functions with
caution. Although all possible safeguards have been incorporated into
them, it is still possible through carelessness to do damage to
important files on your system. Always test editing programs carefully
before committing them to your global site configuration.
@end cartouche





@c .....................................................
@c SUBSECTION
@c .....................................................
@menu
* AbortAtLineMatching::         
* Append::                      
* AppendIfNoLineMatching::      
* AppendIfNoSuchLine::          
* AppendIfNoSuchLinesFromFile::  
* AppendToLineIfNotContains::   
* Audit::                       
* AutoCreate::                  
* AutomountDirectResources::    
* Backup in editfiles::         
* BeginGroupIfDefined::         
* BeginGroupIfNotDefined::      
* BeginGroupIfFileExists::      
* BeginGroupIfFileIsNewer::     
* BeginGroupIfLineContaining::  
* BeginGroupIfLineMatching::    
* BeginGroupIfMatch::           
* BeginGroupIfNoLineContaining::  
* BeginGroupIfNoLineMatching::  
* BeginGroupIfNoMatch::         
* BeginGroupIfNoSuchLine::      
* BreakIfLineMatches::          
* CatchAbort::                  
* CommentLinesMatching::        
* CommentLinesStarting::        
* CommentNLines::               
* CommentToLineMatching::       
* DefineClasses::               
* DefineInGroup::               
* DeleteLinesAfterThisMatching::  
* DeleteLinesContaining::       
* DeleteLinesMatching::         
* DeleteLinesStarting::         
* DeleteLinesNotContaining::    
* DeleteLinesNotMatchingFileItems::  
* DeleteLinesNotStartingFileItems::  
* DeleteNLines::                
* DeleteToLineMatching::        
* EditMode (binary)::           
* EditSplit::                   
* EmptyEntireFilePlease::       
* ElseDefineClasses::           
* EndGroup::                    
* EndLoop::                     
* ExpandVariables::             
* ExpireAfter editfiles::       
* Filter::                      
* FixEndOfLine::                
* ForEachLineIn::               
* GotoLastLine::                
* HashCommentLinesContaining::  
* HashCommentLinesMatching::    
* HashCommentLinesStarting::    
* IfElapsed (editing)::         
* IncrementPointer::            
* Inform (editing)::            
* InsertFile::                  
* InsertLine::                  
* LocateLineMatching::          
* PercentCommentLinesContaining::  
* PercentCommentLinesMatching::  
* PercentCommentLinesStarting::  
* Prepend (editing)::           
* PrependIfNoLineMatching::     
* PrependIfNoSuchLine::         
* Recurse (editing)::           
* ReplaceLineWith::             
* ReplaceAll With::             
* ReplaceFirst::                
* ReplaceLinesMatchingField::   
* Repository::                  
* ResetSearch::                 
* RunScript::                   
* RunScriptIfLineMatching::     
* RunScriptIfNoLineMatching::   
* SetCommentStart::             
* SetCommentEnd::               
* SetLine::                     
* SetScript::                   
* SlashCommentLinesContaining::  
* SlashCommentLinesMatching::   
* SlashCommentLinesStarting::   
* SplitOn::                     
* SysLog::                      
* Umask::                       
* UnCommentLinesContaining::    
* UnCommentLinesMatching::      
* UnCommentsNLines::            
* UnCommentToLineMatching::     
* UnsetAbort::                  
* UseShell::                    
* WarnIfFileMissing::           
* WarnIfLineContaining::        
* WarnIfLineMatching::          
* WarnIfLineStarting::          
* WarnIfNoLineContaining::      
* WarnIfNoLineMatching::        
* WarnIfNoLineStarting::        
* WarnIfNoSuchLine::            
@end menu

@node AbortAtLineMatching, Append, editfiles, editfiles
@subsection AbortAtLineMatching

@smallexample

 AbortAtLineMatching @var{quoted-regex}

@end smallexample

This command sets the value of a regular expression. In all editing
operations (except @code{FixEndOfLine} and @code{GotoLastLine}) which involve multiple
replacements and searches, this expression marks a boundary
beyond which cfengine will cease to look any further. In other
words, if cfengine encounters a line matching this regular
expression, it aborts the current action. BE CAREFUL with this
feature: once set, the string remains set for the remainder of
the current file. It might therefore interact in unsuspected ways
with other search parameters. Editing actions are always aborted
as soon as the abort expression is matched.
Use @code{UnsetAbort} to unset the feature.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node Append, AppendIfNoLineMatching, AbortAtLineMatching, editfiles
@subsection Append

@smallexample

 Append @var{quoted-regex}

@end smallexample


Add a line containing the quoted string to the end of the file.
This should be used in conjunction with the
decision structures @code{BeginGroupIfNoLineMatching} and
@code{BreakIfLineMatches}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AppendIfNoLineMatching, AppendIfNoSuchLine, Append, editfiles
@subsection AppendIfNoLineMatching


@smallexample

  AppendIfNoLineMatching  @var{quoted-regex}/ ``ThisLine''

@end smallexample


A new version of the older @code{AppendIfNoSuchLine}
which uses a regular expression instead of a literal
string. The line which gets appended must be set
previously using @code{SetLine}. If @code{``ThisLine''} is
given as the argument, the current value of then line buffer
is assumed. This allows constructions for merging files
on a convergent line-by-line basis:

@smallexample

editfiles:

 @{ /tmp/bla

 ForEachLineIn "/tmp/in"
    AppendIfNoLineMatching "ThisLine"
 EndLoop
 @}

@end smallexample
@cindex Merging files.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AppendIfNoSuchLine, AppendIfNoSuchLinesFromFile, AppendIfNoLineMatching, editfiles
@subsection AppendIfNoSuchLine

@smallexample

  AppendIfNoSuchLine @var{quoted-string}

@end smallexample

Add a line containing the quoted string to the end of the file
if the file doesn't contain the exact line already.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AppendIfNoSuchLinesFromFile, AppendToLineIfNotContains, AppendIfNoSuchLine, editfiles
@subsection   AppendIfNoSuchLinesFromFile

@smallexample

  AppendIfNoSuchLinesFromFile @var{filename}

@end smallexample

For each line in the named file, call AppendIfNoSuchLine.  This adds
lines containing the strings listed in the named file to the end of the
current file if the file doesn't contain the exact line already.
@cindex @code{AppendIfNoSuchLinesFromFile}

@c .....................................................
@c SUBSECTION
@c .....................................................

@node AppendToLineIfNotContains, Audit, AppendIfNoSuchLinesFromFile, editfiles
@subsection AppendToLineIfNotContains

@smallexample

 AppendToLineIfNotContains @var{quoted-string}

@end smallexample

This commands looks for an exact match of the quoted string
in the current line. If the quoted string is not contained
in the line, it is appended. This may be used for adding
entries to a list.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Audit, AutoCreate, AppendToLineIfNotContains, editfiles
@subsection Audit in editfiles

@smallexample

 Audit @var{true/false}

@end smallexample


Local decision about whether this edit stanza will be audited. Requires
auditing to be on globally for this to have an effect.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node AutoCreate, AutomountDirectResources, Audit, editfiles
@subsection AutoCreate

If this command is listed anywhere in the file action list, cfengine
will create the named file if it doesn't exist. Normally cfengine issues
an error if the named file does not exist, but if this is set,
notification of the file's absence is only in verbose output. New files
are created with mode 644 (see also Umask), read access for everyone and write access for
the cfengine user (normally root). Note that if you set this,
BeginGroupIfFileIsNewer will always be true.
@cindex @code{AutoCreate}
@mbindex How to create files while editing

@c .....................................................
@c SUBSECTION
@c .....................................................
@node AutomountDirectResources, Backup in editfiles, AutoCreate, editfiles
@subsection AutomountDirectResources

@smallexample

AutomountDirectResources @var{quoted-string}

@end smallexample

This command is designed to assist with automounter configuration for
users wishing to use the automounter for NFS filesystems, but still use
the cfengine mount model.
@cindex NFS mount model and automounter
@cindex automounter
Applied to the current file, it is equivalent to saying: for each of the
mountable resources in the list @xref{mountables}, append if not found a
line for a direct automount map command, to the current file.  The
string which follows can be used to specify any special mount options
e.g. @code{``-nosuid''} for non setuid mounting (of all the
mountables). Note that this is added to the current file and not to a
file named @file{/etc/auto_direct}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Backup in editfiles, BeginGroupIfDefined, AutomountDirectResources, editfiles
@subsection Backup in editfiles

@smallexample

 Backup @var{quoted-string}

@end smallexample

Set to true or false, on or off to set backup policy for this file.
Default is on.  The default is to produce time-stamped backups of
files; this may be coded explicitly by setting to ``timestamp'' or
``stamp''. If set to ``false'' or ``off'', no backup is kept of the
edited file. If the value is set to ``single'' or ``one'' then only
the last version of the file is kept, overwriting any previously saved
versions.

See @ref{copybackup}.

@smallexample
   Backup "single"
@end smallexample 
@cindex Backup

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfDefined, BeginGroupIfNotDefined, Backup in editfiles, editfiles
@subsection BeginGroupIfDefined

@smallexample

BeginGroupIfDefined @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted class is defined. Edit groups may be nested.
@cindex @code{BeginGroupIfDefined}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfNotDefined, BeginGroupIfFileExists, BeginGroupIfDefined, editfiles
@subsection BeginGroupIfNotDefined

@smallexample

BeginGroupIfNotDefined @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted class is not defined. Edit groups may be nested.
@cindex @code{BeginGroupIfNotDefined}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfFileExists, BeginGroupIfFileIsNewer, BeginGroupIfNotDefined, editfiles
@subsection BeginGroupIfFileExists

@smallexample

 BeginGroupIfFileExists @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted filename exists (can be statted).
Files which are not readable by the running process are
for all intents and purposes non-existent. Edit groups may be nested.
@cindex @code{BeginGroupIfFileExists}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfFileIsNewer, BeginGroupIfLineContaining, BeginGroupIfFileExists, editfiles
@subsection BeginGroupIfFileIsNewer

@smallexample

 BeginGroupIfFileIsNewer @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted filename is newer than the file being
edited. Edit groups may be nested.
@cindex @code{BeginGroupIfFileIsNewer}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfLineContaining, BeginGroupIfLineMatching, BeginGroupIfFileIsNewer, editfiles
@subsection BeginGroupIfLineContaining

@smallexample

BeginGroupIfLineContaining @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted string appears in
any line in the file. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfLineMatching, BeginGroupIfMatch, BeginGroupIfLineContaining, editfiles
@subsection BeginGroupIfLineMatching

@smallexample

BeginGroupIfLineMatching @var{quoted-regex}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted regular expression
matches any line in the file. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfMatch, BeginGroupIfNoLineContaining, BeginGroupIfLineMatching, editfiles
@subsection BeginGroupIfMatch

@smallexample

 BeginGroupIfMatch @var{quoted-regex}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted regular expression matches the current line. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfNoLineContaining, BeginGroupIfNoLineMatching, BeginGroupIfMatch, editfiles
@subsection BeginGroupIfNoLineContaining

@smallexample

BeginGroupIfNoLineContaining @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted string does not appear in
any line in the file. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfNoLineMatching, BeginGroupIfNoMatch, BeginGroupIfNoLineContaining, editfiles
@subsection BeginGroupIfNoLineMatching

@smallexample

BeginGroupIfNoLineMatching @var{quoted-regex}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted regular expression
does not match any line in the file. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfNoMatch, BeginGroupIfNoSuchLine, BeginGroupIfNoLineMatching, editfiles
@subsection BeginGroupIfNoMatch

@smallexample

BeginGroupIfNoMatch @var{quoted-regex}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted regular expression does
not match the current line. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BeginGroupIfNoSuchLine, BreakIfLineMatches, BeginGroupIfNoMatch, editfiles
@subsection BeginGroupIfNoSuchLine

@smallexample

 BeginGroupIfNoSuchLine @var{quoted-string}

@end smallexample

The lines following, up to the first @code{EndGroup}
are executed if the quoted literal string
does not match any line in the file. Edit groups may be nested.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node BreakIfLineMatches, CatchAbort, BeginGroupIfNoSuchLine, editfiles
@subsection BreakIfLineMatches 

@smallexample

BreakIfLineMatches  @var{quoted-regex}

@end smallexample

Terminates further editing of the current
file if the current line matches the quoted
regular expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node CatchAbort, CommentLinesMatching, BreakIfLineMatches, editfiles
@subsection CatchAbort
@cindex CatchAbort
Edit actions which abort on failure (such as @code{LocateLineMatching})
will jump to the first instance of this marker instead of completely
aborting an edit if this keyword occurs in an editing script.
You can catch the exceptions thrown by the following commands:
@code{CommentNLines},@code{CommentToLineMatching},@code{DeleteNLines},@code{DeleteToLineMatching},
@code{HashCommentToLineMatching},@code{IncrementPointer},
@code{LocateLineMatching},@code{PercentCommentToLineMatching},
@code{RunScriptIf(No)LineMatching},@code{UnCommentNLines}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node CommentLinesMatching, CommentLinesStarting, CatchAbort, editfiles
@subsection CommentLinesMatching

@smallexample

CommentLinesMatching  @var{quoted-regex}

@end smallexample

Use the current value of the comment delimiters
set using @code{SetCommentStart} and @code{SetCommentEnd} to comment
out lines matching the given regular expression in quotes.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node CommentLinesStarting, CommentNLines, CommentLinesMatching, editfiles
@subsection CommentLinesStarting

@smallexample

CommentLinesStarting  @var{quoted-string} 

@end smallexample

Use the current value of the comment delimiters
set using @code{SetCommentStart} and @code{SetCommentEnd} to comment
out lines starting with the quoted literal string.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node CommentNLines, CommentToLineMatching, CommentLinesStarting, editfiles
@subsection CommentNLines

@smallexample

CommentNLines @var{quoted-string}

@end smallexample

Comments up to @math{N} lines from the current file, starting from the
location of the current line pointer. If the end of the file is reached
and less than @math{N} lines are deleted, a warning is issued, but
editing continues. The current value of the comment delimiters is
used to determine the method of commenting, (see @code{SetCommentStart}).
After the operation the pointer points to the line after the
commented lines.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node CommentToLineMatching, DefineClasses, CommentNLines, editfiles
@subsection CommentToLineMatching

@smallexample

CommentToLineMatching  @var{quoted-regex}

@end smallexample

Use the current value of the comment delimiters set using
@code{SetCommentStart} and @code{SetCommentEnd} to comment out lines
from the current position in a file to a line matching the given regular
expression in quotes.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DefineClasses, DefineInGroup, CommentToLineMatching, editfiles
@subsection DefineClasses

@smallexample

DefineClasses "@var{class1}:@var{class2}:..."

@end smallexample

Activate the following colon, comma or dot-separated list of classes if
and only if the file is edited. 

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DefineInGroup, DeleteLinesAfterThisMatching, DefineClasses, editfiles
@subsection DefineInGroup

@smallexample

DefineInGroup "@var{class1}:@var{class2}:..."

@end smallexample 

Activate the following colon, comma or dot-separated list of classes if
the edit group is entered. This can be combined with other classes
to identify what particular edits took place.
Use DefineInGroup if you want to define a class or list of classes
conditional on entry to a BeginGroup ... EngGroup block. For example,

@smallexample
editfiles:
    @{ /etc/inetd.conf
      BeginGroupIfNoSuchLine "$(myservice1)"
        Append "$(myservice1)"
	DefineInGroup "myservice1_added"
      EndGroup

      BeginGroupIfNoSuchLine "$(myservice2)"
        Append "$(myservice2)"
	DefineInGroup "myservice2_added"
      EndGroup
    @}
@end smallexample
@noindent
This will define service_added and service_added_another_way if
either line is added, but additionally myservice1_added if myservice1
was added and likewise for myservice2_added.

Activate the following colon, comma or dot-separated list of classes
if execution reaches the @code{BeginGroup} ... @code{EndGroup}
section(s) containing this command. If you think you want to put
DefineClasses within a @code{BeginGroup} ... @code{EndGroup} section,
you actually want this.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesAfterThisMatching, DeleteLinesContaining, DefineInGroup, editfiles
@subsection DeleteLinesAfterThisMatching

@smallexample

 DeleteLinesAfterThisMatching @var{quoted-regex}

@end smallexample

Delete lines after the current position which match the quoted expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesContaining, DeleteLinesMatching, DeleteLinesAfterThisMatching, editfiles
@subsection   DeleteLinesContaining/DeleteLinesNotContaining

@smallexample

 DeleteLinesContaining @var{quoted-string}
 DeleteLinesNotContaining @var{quoted-string}

@end smallexample
Delete all lines (not) containing the exact string quoted.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesMatching, DeleteLinesStarting, DeleteLinesContaining, editfiles
@subsection   DeleteLinesMatching/DeleteLinesNotMatching

@smallexample

   DeleteLinesMatching @var{quoted-regex}
   DeleteLinesNotMatching @var{quoted-regex}

@end smallexample

Delete all lines (not) fully matching the tied quoted regular expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesStarting, DeleteLinesNotContaining, DeleteLinesMatching, editfiles
@subsection  DeleteLinesStarting/DeleteLinesNotStarting

@smallexample

   DeleteLinesStarting @var{quoted-string}
   DeleteLinesNotStarting @var{quoted-string}

@end smallexample

Delete all lines (not) beginning with the exact string quoted.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesNotContaining, DeleteLinesNotMatchingFileItems, DeleteLinesStarting, editfiles
@subsection DeleteLinesNotContainingFileItems

@smallexample

DeleteLinesNotContainingFileItems @var{filename}

@end smallexample
Delete lines in the file that do not contain the any of the substrings in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesNotMatchingFileItems, DeleteLinesNotStartingFileItems, DeleteLinesNotContaining, editfiles
@subsection DeleteLinesNotMatchingFileItems

@smallexample

 DeleteLinesNotMatchingFileItems @var{filename}

@end smallexample

Delete lines in the file that do not match the any of the regular expressions in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteLinesNotStartingFileItems, DeleteNLines, DeleteLinesNotMatchingFileItems, editfiles
@subsection DeleteLinesNotStartingFileItems

@smallexample

DeleteLinesNotStartingFileItems @var{filename}

@end smallexample

Delete lines in the file that do not start with any of the substrings in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteNLines, DeleteToLineMatching, DeleteLinesNotStartingFileItems, editfiles
@subsection DeleteNLines

@smallexample

DeleteNLines @var{quoted-string}

@end smallexample

Deletes up to @math{N} lines from the current file, starting from the
location of the current line pointer. If the end of the file is reached
and less than @math{N} lines are deleted, a warning is issued, but
editing continues.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node DeleteToLineMatching, EditMode (binary), DeleteNLines, editfiles
@subsection DeleteToLineMatching

@smallexample

DeleteToLineMatching @var{quoted-regex}

@end smallexample

Delete lines from the current position, up to
but not including a line matching the regular expression
in the quoted string. If no line matches the
given expression, a warning is only printed in
verbose mode, but all edits are immediately
abandoned.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node EditMode (binary), EditSplit, DeleteToLineMatching, editfiles
@subsection EditMode and binary editing

If set to binary, the file will be edited as if it were a non-ASCII file.
See discussion below.

@smallexample

   EditMode "Binary"

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node EditSplit, EmptyEntireFilePlease, EditMode (binary), editfiles
@subsection EditSplit
Editfiles treats lists as private interpretations, since iteration over
lists could lead to unpredictable behaviour if text variables accidentally
contain the list separator. The control option @code{Split} therefore has
no effect on editfiles. This definition makes list expansion work in editfiles.

@smallexample

   EditSplit ","

@end smallexample
@vindex EditSplit
@vindex Split
@cindex Split in editfiles
@cindex Iteration over lists (editfiles)

Be careful not to confuse this with the @code{SplitOn} character.

@smallexample

editfiles:

 @{ /tmp/bla1

 EditSplit "!"
 AppendIfNoSuchLine "alpha1!beta1"
 EditSplit ":"
 AppendIfNoSuchLine "alpha2!beta2"
 EditSplit "@@"
 AppendIfNoSuchLine "alpha3@@beta3"
 @} 

 @{ /tmp/bla2

 AppendIfNoSuchLine "new1@@new2"
 @}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node EmptyEntireFilePlease, ElseDefineClasses, EditSplit, editfiles
@subsection EmptyEntireFilePlease
Deletes all lines from the current file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ElseDefineClasses, EndGroup, EmptyEntireFilePlease, editfiles
@subsection ElseDefineClasses
See @code{DefineClasses}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node EndGroup, EndLoop, ElseDefineClasses, editfiles
@subsection EndGroup
Terminates a begin-end conditional structure.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node EndLoop, ExpandVariables, EndGroup, editfiles
@subsection EndLoop
Terminates a loop. See @code{ForEachLineIn}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ExpandVariables, ExpireAfter editfiles, EndLoop, editfiles
@subsection ExpandVariables
This causes cfengine to run through the contents of the file
and expand any recognisable editfile strings in the file, if they
are defined within the scope of the cfagent script. This gives
cfengine an m4 like capacity.
@cindex ExpandVariables
@cindex Templates
@cindex m4 functionality

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ExpireAfter editfiles, Filter, ExpandVariables, editfiles
@subsection ExpireAfter editfiles
 
@smallexample

ExpireAfter @var{mins}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Filter, FixEndOfLine, ExpireAfter editfiles, editfiles
@subsection Filter
Name a fiter for pruning file searches.


@smallexample

Filter @var{filteralias}

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................
@node FixEndOfLine, ForEachLineIn, Filter, editfiles
@subsection FixEndOfLine

The quoted string which follows may be either @samp{dos}
or @samp{Unix} to fix the end of line character conventions
to match these systems. This command should be executed
last of all, since cfengine appends new lines with the conventions
of the system on which is was complied during edit operations.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ForEachLineIn, GotoLastLine, FixEndOfLine, editfiles
@subsection ForEachLineIn @var{quoted-filename}

@smallexample

ForEachLineIn @var{quoted-filename}

@end smallexample

This marks the beginning of a for-loop which reads successive
lines from a named file. The result is like using @code{SetLine}
for each line in the file. Nested loops are not permitted.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node GotoLastLine, HashCommentLinesContaining, ForEachLineIn, editfiles
@subsection GotoLastLine
Moves the file pointer to the last line in
the current file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node HashCommentLinesContaining, HashCommentLinesMatching, GotoLastLine, editfiles
@subsection   HashCommentLinesContaining
Add a @samp{#} to the start of any line containing the quoted string.

@smallexample

  HashCommentLinesContaining @var{quoted-string}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node HashCommentLinesMatching, HashCommentLinesStarting, HashCommentLinesContaining, editfiles
@subsection   HashCommentLinesMatching
Add a @samp{#} to the start of any line exactly matching the quoted regular expression.

@smallexample

 HashCommentLinesMatching @var{quoted-regex}

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................
@node HashCommentLinesStarting, IfElapsed (editing), HashCommentLinesMatching, editfiles
@subsection   HashCommentLinesStarting
Add a @samp{#} to the start of any line starting with the quoted string.

@smallexample

 HashCommentLinesStarting @var{quoted-string}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node IfElapsed (editing), IncrementPointer, HashCommentLinesStarting, editfiles
@subsection IfElapsed

@smallexample

ExpireAfter @var{mins}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node IncrementPointer, Inform (editing), IfElapsed (editing), editfiles
@subsection IncrementPointer @var{quoted-number}

@smallexample

 IncrementPointer @var{quoted-number}

@end smallexample

Increments the value (in lines) of the file pointer
by the number of lines specified in the quoted
string (as a denary number). e.g. @samp{``4''}.
Negative values are equivalent to decrementing the
pointer. If a request is made to increment/decrement
outside of the file boundaries the pointer `bumps'
into the boundary and remains there, i.e. either at
start of file or end of file.
@cindex Incrementing line pointer in editfiles
@cindex Decrementing line pointer in editfiles

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Inform (editing), InsertFile, IncrementPointer, editfiles
@subsection Inform editfiles

@smallexample

 Inform @var{quoted-string}

@end smallexample

Set to @code{true} or @code{false}, @code{on} or @code{off} to set the
inform level for this file.  Default is @code{off}. Note that, owing to the
way that cfengine re-uses code, this feature does not work very
well. Detailed messages are not available, only a summary of whether
or not the file changed.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node InsertFile, InsertLine, Inform (editing), editfiles
@subsection InsertFile

@smallexample

 InsertFile @var{quoted-string}

@end smallexample

Inserts the named file after the current line position
in the file. This should be used in conjunction
with a begin-end construction in order to avoid
including the file every time cfengine is run.
If the file does not exist, or cannot be opened,
there is only a warning issued in verbose mode.
Note if the file is empty, or if the current line
pointer is not set, the file is inserted at the start
of the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node InsertLine, LocateLineMatching, InsertFile, editfiles
@subsection InsertLine 

@smallexample

 InsertFile @var{quoted-string}

@end smallexample

Inserts the quoted string as a line after the current
line pointer in the file. After the insert, the line
pointer is incremented by one so that subsequent
inserted lines are placed after the first.
This should probably be used in conjunction with the
conditional begin-end tests to avoid lines being
inserted on every run.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node LocateLineMatching, PercentCommentLinesContaining, InsertLine, editfiles
@subsection LocateLineMatching

@smallexample

LocateLineMatching @var{quoted-regex}

@end smallexample

Moves the current line pointer to the line matching the
quoted regular expression. If there is no match, a
warning is only issued in verbose mode, but all 
editing is immediately aborted. See also
@code{WarnIfNoLineMatching} so that you can get an 
explicit warning, even out of verbose mode.


@c .....................................................
@c SUBSECTION
@c .....................................................
@node PercentCommentLinesContaining, PercentCommentLinesMatching, LocateLineMatching, editfiles
@subsection   PercentCommentLinesContaining

@smallexample

  PercentCommentLinesContaining @var{quoted-string}

@end smallexample

Add a @samp{%} to the start of any line containing the quoted string.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node PercentCommentLinesMatching, PercentCommentLinesStarting, PercentCommentLinesContaining, editfiles
@subsection   PercentCommentLinesMatching

@smallexample

  PercentCommentLinesMatching @var{quoted-regex}

@end smallexample

Add a @samp{%} to the start of any line exactly matching the quoted regular.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node PercentCommentLinesStarting, Prepend (editing), PercentCommentLinesMatching, editfiles
@subsection   PercentCommentLinesStarting

@smallexample

   PercentCommentLinesStarting @var{quoted-string}

@end smallexample

Add a @samp{%} to the start of any line starting with the quoted string.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Prepend (editing), PrependIfNoLineMatching, PercentCommentLinesStarting, editfiles
@subsection Prepend

@smallexample

 Prepend @var{quoted-string}

@end smallexample

Add a line containing the quoted string to the start of the file.
This should be used in conjunction with the
decision structures @code{BeginGroupIfNoLineMatching} and
@code{BreakIfLineMatches}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node PrependIfNoLineMatching, PrependIfNoSuchLine, Prepend (editing), editfiles
@subsection PrependIfNoLineMatching

@smallexample

PrependIfNoLineMatching @var{quoted-regex}

@end smallexample

A new version of the older @code{PrependIfNoSuchLine}
with uses a regular expression instead of a literal string.
The string prepended is the one set using @code{SetLine}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node PrependIfNoSuchLine, Recurse (editing), PrependIfNoLineMatching, editfiles
@subsection   PrependIfNoSuchLine

@smallexample

  PrependIfNoSuchLine @var{quoted-string}

@end smallexample

Add a line containing the quoted string to the start of the file
if the file doesn't contain the exact line already.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Recurse (editing), ReplaceLineWith, PrependIfNoSuchLine, editfiles
@subsection  Recurse

@smallexample

 Recurse @var{digit/inf}

@end smallexample

For recursive descents when editing whole file trees. 

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ReplaceLineWith, ReplaceAll With, Recurse (editing), editfiles
@subsection ReplaceLineWith

@smallexample

 ReplaceLineWith @var{quoted-string}

@end smallexample

Replace the line at the current position with the
text in the quoted string. The file pointer remains
pointing to this line after the change.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ReplaceAll With, ReplaceFirst, ReplaceLineWith, editfiles
@subsection ReplaceAll/With

@smallexample

 ReplaceAll @var{quoted-regex} With @var{quoted-string}

@end smallexample

Replace all instances of strings matching the regular expression in the
first quotes with the exact string in the second set of quotes,
throughout the current file. Note that cfengine matches on a left to
right basis, with the first match taking precedence, so if your regular
expression matches text ambiguously it is the first occurrence which is
replaced. For example, if you replace @samp{cf.*} with @samp{CFENGINE}
and cfengine encounters a line @samp{hello cfengine cfengine}, then this
will be replaced with @samp{hello CFENGINE} even though two possible
strings match the regular expression. On the other hand if the
expression is not ambiguous, say replacing @samp{cfengine} with
@samp{CFENGINE}, then the result would be @samp{hello CFENGINE CFENGINE}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ReplaceFirst, ReplaceLinesMatchingField, ReplaceAll With, editfiles
@subsection ReplaceFirst/With

@smallexample

 ReplaceFirst @var{quoted-regex} With @var{quoted-string}

@end smallexample

For each line of the current file, replace the first string matching the
regular expression in the first quotes (@var{quoted-regex}) with the
string given in the second set of quotes (@var{quoted-string}).
Matching is done left to right.  For example, if you replace
@samp{``YY = [[:digit:]][[:digit:]]''} with @samp{``YY = 04''} and
cfengine encounters @samp{``YY = 03 but old YY = 70''} then it will
be replaced with @samp{``YY = 04 but old YY = 70''}

@c .....................................................
@c SUBSECTION
@c .....................................................
@node ReplaceLinesMatchingField, Repository, ReplaceFirst, editfiles
@subsection ReplaceLinesMatchingField

@smallexample

ReplaceLinesMatchingField @var{quoted-number}

@end smallexample

This command replaces any lines in the current file with the current line
set by @code{SetLine} or @code{ForEachLineIn}, if the lines
are split into fields (e.g. the password file) separated by the
@code{SplitOn} character (':' by default), and the corresponding
fields match.

The idea behind this command was to be able to override global
passwords (from a file which gets distributed) by new passwords 
in a local file. Rather than maintaining the files separately,
this simply overrides the entries with the new ones.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Repository, ResetSearch, ReplaceLinesMatchingField, editfiles
@subsection Repository editfiles

@smallexample

Repository @var{quoted string}

@end smallexample

This allows a local override of the @code{Repository} variable, on an item
by item basis. If set to ``off'' or ``none'' it cancels the value of a global repository.

See @ref{copybackup}.
See @ref{Backup in editfiles}.


@c .....................................................
@c SUBSECTION
@c .....................................................
@node ResetSearch, RunScript, Repository, editfiles
@subsection ResetSearch

@smallexample

 ResetSearch @var{quoted-string}

@end smallexample

Sets the current-position pointer to the line number
in the quoted string. @samp{EOF} indicates the end of
the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node RunScript, RunScriptIfLineMatching, ResetSearch, editfiles
@subsection RunScript

@smallexample

RunScript @var{quoted-string}

@end smallexample


Executes the named script command. Before executing the script any edits
are saved to disk. After the script has executed,
cfengine reloads the file for any further editing
operations. The script (which may be any executable
program) is appended with two arguments: the name of the
file which is being edited and the system hard class
(e.g. sun4, ultrix etc.) of the system executing
the script.

CAUTION: cfengine knows nothing about
the success or failure of anything that is done during the
execution of user scripts. This feature is to be
used at the users own peril!

@c .....................................................
@c SUBSECTION
@c .....................................................
@node RunScriptIfLineMatching, RunScriptIfNoLineMatching, RunScript, editfiles
@subsection RunScriptIfLineMatching

@smallexample

RunScriptIfLineMatching @var{quoted-string}

@end smallexample

Executes the script named with the @code{SetScript}
command only if the current file contains a line matching
the quoted regular expression.

CAUTION: cfengine knows nothing about
the success or failure of anything that is done during the
execution of user scripts. This feature is to be
used at the users own peril!

@c .....................................................
@c SUBSECTION
@c .....................................................
@node RunScriptIfNoLineMatching, SetCommentStart, RunScriptIfLineMatching, editfiles
@subsection RunScriptIfNoLineMatching

@smallexample

RunScriptIfNoLineMatching @var{quoted-regex}

@end smallexample

Executes the script named with the @code{SetScript}
command if the current file contains no line matching
the quoted regular expression.

CAUTION: cfengine knows nothing about
the success or failure of anything that is done during the
execution of user scripts. This feature is to be
used at the users own peril!

@c .....................................................
@c SUBSECTION
@c .....................................................

@node SetCommentStart, SetCommentEnd, RunScriptIfNoLineMatching, editfiles
@subsection SetCommentStart

@smallexample

 SetCommentStart @var{quoted-string}

@end smallexample

Specify which string should be used for starting
a comment using the commands @code{CommentLineMatching}
and @code{CommentLineStarting}. The default is the hash
symbol @samp{#} followed by a single space.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SetCommentEnd, SetLine, SetCommentStart, editfiles
@subsection SetCommentEnd

@smallexample

 SetCommentEnd  @var{quoted-string}

@end smallexample

Specify which string should be used for ending
a comment using the commands @code{CommentLineMatching}
and @code{CommentLineStarting}. The default is the empty
string. For example, you could make C style comments
by setting CommentStart to @samp{/*} and comment
end to @samp{*/}.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SetLine, SetScript, SetCommentEnd, editfiles
@subsection SetLine

@smallexample

 SetLine @var{quoted-string}

@end smallexample

Sets a current line value which can be appended using
@code{AppendIfNoLineMatching} using a regular expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SetScript, SlashCommentLinesContaining, SetLine, editfiles
@subsection SetScript

@smallexample

 SetScript @var{quoted-string}

@end smallexample

Sets the name of a user-supplied script
for editing the current file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SlashCommentLinesContaining, SlashCommentLinesMatching, SetScript, editfiles
@subsection   SlashCommentLinesContaining

@smallexample

  SlashCommentLinesContaining @var{quoted-string}

@end smallexample

Add a @samp{//} to the start of any line containing the quoted string.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SlashCommentLinesMatching, SlashCommentLinesStarting, SlashCommentLinesContaining, editfiles
@subsection   SlashCommentLinesMatching

@smallexample

  SlashCommentLinesMatching @var{quoted-regex}

@end smallexample

Add a @samp{//} to the start of any line exactly matching the quoted regular expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SlashCommentLinesStarting, SplitOn, SlashCommentLinesMatching, editfiles
@subsection   SlashCommentLinesStarting

@smallexample

  SlashCommentLinesStarting @var{quoted-string}

@end smallexample

Add a @samp{//} to the start of any line starting with the quoted string.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SplitOn, SysLog, SlashCommentLinesStarting, editfiles
@subsection SplitOn

@smallexample

 SplitOn @var{quoted-string}

@end smallexample

This defines a single character which is to be interpreted as a
field separator for editing files with columns. The default value
for this is @samp{:}, as is used in the password and group files.
It is used in conjunction with @code{ReplaceLinesMatchingField}.
Note, be careful not to confuse this with the @code{EditSplit} character.
@cindex SplitOn
@cindex Password file, editing
@cindex Group field, editing
@cindex Field separator in editfiles

@c .....................................................
@c SUBSECTION
@c .....................................................
@node SysLog, Umask, SplitOn, editfiles
@subsection Syslog editfiles
Set to true or false, on or off to set inform level for this file.
Default is off.

@smallexample

Syslog @var{quoted-string}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Umask, UnCommentLinesContaining, SysLog, editfiles
@subsection Umask

@smallexample

 @var{quote mode}

@end smallexample

Set local umask for file creation and script execution.
@cindex umask

@c .....................................................
@c SUBSECTION
@c .....................................................
@node UnCommentLinesContaining, UnCommentLinesMatching, Umask, editfiles
@subsection UnCommentLinesContaining

@smallexample
 UnCommentLinesContaining  @var{quoted-string}

@end smallexample

Uncomment all lines in file containing the quoted string as a
substring. The comment delimiters are assumed to be those
set using SetCommentStart and SetCommentEnd.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node UnCommentLinesMatching, UnCommentsNLines, UnCommentLinesContaining, editfiles
@subsection UnCommentLinesMatching

@smallexample

UnCommentLinesMatching  @var{quoted-regex}

@end smallexample

Uncomment all lines in file matching the quoted regular expression.  The
comment delimiters are assumed to be those set using SetCommentStart and
SetCommentEnd.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node UnCommentsNLines, UnCommentToLineMatching, UnCommentLinesMatching, editfiles
@subsection UnCommentNLines

@smallexample

 UnCommentNLines @var{quoted-string}

@end smallexample

Uncomments N lines starting from the current position, using
the currently defined method for commenting. Note that the
comment start and end symbols are removed independently, i.e.
they are not matched, so that a comment may be spread over
several lines. e.g. If using C style @samp{/*} and @samp{*/}
comments, the command @code{UnCommentNLines "3"} would
uncomment

@smallexample
 /* 1 */
 /* 2 */
 /* 3 */
@end smallexample
@noindent
and also

@smallexample
 /* 1 
    2
    3 */
@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node UnCommentToLineMatching, UnsetAbort, UnCommentsNLines, editfiles
@subsection UnCommentToLineMatching

@smallexample

UnCommentToLineMatching @var{quoted-string}

@end smallexample

Uncomments from the current position up to and including the first
line matching the named regular expression.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node UnsetAbort, UseShell, UnCommentToLineMatching, editfiles
@subsection UnsetAbort
Switches off the feature @code{AbortAtLineMatching}.

@smallexample

 UnsetAbort  @var{quoted-string}

@end smallexample


@c .....................................................
@c SUBSECTION
@c .....................................................
@node UseShell, WarnIfFileMissing, UnsetAbort, editfiles
@subsection UseShell

Normally cfengine uses a shell based exec function to run
scripts during editing. This involves the inheritance of
environment variables and path, which carries with it an
inherent security risk. Setting this value to false
causes execution to execute without an encapsulating shell.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfFileMissing, WarnIfLineContaining, UseShell, editfiles
@subsection   WarnIfFileMissing
If the file to be edited does not exist, a visible alert
is issued.

@smallexample

  WarnIfFileMissing @var{quoted-string}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfLineContaining, WarnIfLineMatching, WarnIfFileMissing, editfiles
@subsection   WarnIfLineContaining
Issue a warning if the quoted string is found as a
substring of one or more lines in the file.

@smallexample

   WarnIfLineContaining @var{quoted-string}

@end smallexample

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfLineMatching, WarnIfLineStarting, WarnIfLineContaining, editfiles
@subsection   WarnIfLineMatching

@smallexample

  WarnIfLineMatching @var{quoted-regex}

@end smallexample

Issue a warning if the quoted regular expression
matches one or more lines in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfLineStarting, WarnIfNoLineContaining, WarnIfLineMatching, editfiles
@subsection   WarnIfLineStarting

@smallexample

  WarnIfLineStarting @var{quoted-string}

@end smallexample

Issue a warning if the quoted string matches the start
of one or more lines in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfNoLineContaining, WarnIfNoLineMatching, WarnIfLineStarting, editfiles
@subsection   WarnIfNoLineContaining

@smallexample

  WarnIfNoLineContaining @var{quoted-string}

@end smallexample

Issue a warning if the quoted string is not contained
in one or more lines in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfNoLineMatching, WarnIfNoLineStarting, WarnIfNoLineContaining, editfiles
@subsection   WarnIfNoLineMatching

@smallexample

  WarnIfNoLineMatching @var{reg-ex}

@end smallexample

Issue a warning if the quoted regular expression does not match
one or more lines in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfNoLineStarting, WarnIfNoSuchLine, WarnIfNoLineMatching, editfiles
@subsection WarnIfNoLineStarting

@smallexample

WarnIfNoLineStarting @var{quoted-string}

@end smallexample

Issue a warning if the quoted string is not found
at the start of one or more lines in the file.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node WarnIfNoSuchLine,  , WarnIfNoLineStarting, editfiles
@subsection WarnIfNoSuchLine

@smallexample

WarnIfNoSuchLine @var{quoted-regex}

@end smallexample

Issue a warning if the quoted regular expression does not
match one or more lines in the file.


@c %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@c SECTION
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

@node Editfiles on Binary Files, files, editfiles, Cfagent reference
@section Editfiles on Binary Files

@noindent
A limited number of operations can also be performed on purely binary
files, e.g.  compiled programs, in order to search for strings or
viral code, or to modify strings within a program. Binary mode is a
mutually exclusive, separate mode to normal editing. The limit on the
size of binary files is set by @code{editbinaryfilesize} in
@code{control}.


@itemize @bullet

@item  ReplaceAll @var{regex} With @var{literal}

Replaces occurrences of the matched regular expression with\
the provided literal text, only if the length of the literal substitute
is less than or equal to the length of the located string. If the 
replacement string is shorter, it is padded with ascii spaces (character 32) by default.
The padding character can be changed by setting @code{BinaryPaddingChar} in @code{control}.
Padding with a null byte would lead to corruption of text within a program.

@item  WarnIfContainsString @var{regex/literal}
Yields a warning if the literal string or regular expression matches.
Cfengine first attempts a literal match and then a regular expression
match.

@item  WarnIfContainsFile @var{filename}
Yields a warning if the contents of the named file exactly match
part of the file which is being edited. This can be used to search for
binary data which cannot be typed directly into the cfengine program,
e.g. virus signatures.

@end itemize


@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node files, filters, Editfiles on Binary Files, Cfagent reference
@section files
@cindex File management
@cindex Files, checking permissions
@cindex Files, setting owner
@vindex files

The @code{files} facility allows you to touch (create), check for the
existence, owner and permissions of files, change the permissions and
test for setuid root programs.

@c .....................................................
@c SUBSECTION
@c .....................................................

@menu
* Syntax::                      
* Recursion::                   
* Directory permissions::       
* Checksums and change management::  
* home directive::              
* Owner and group wildcards::   
* Files linkchildren::          
* touch::                       
* create::                      
@end menu

@node Syntax, Recursion, files, files
@subsection Syntax
@cindex Files, syntax

A files-statement can have several options.  We can begin by examining
the form of the statement in pseudo-code:

@cartouche

@w{}
@smallexample
  files:

     @var{classes}::

        /@var{file-object}
                          mode=@var{mode}
                          owner=@var{uid-list}
                          group=@var{gid-list}
                          action=@var{fixall/other-options}/@b{warnall} 
                          links=@b{false/stop}@var{/traverse/follow/tidy}
                          rxdirs=@b{true/on}/@var{false/off}

                          ignore=@var{pattern}
                          include=@var{pattern}
                          exclude=@var{pattern}
                          filter=@var{filter alias}
                          xdev=@var{true/on}/@b{false/off}

                          define=@var{classlist}
                          elsedefine=@var{classlist}

                          checksum=@var{md5/sha/best}
                          syslog=@var{true/on}/@b{false/off}
                          inform=@var{true/on}/@b{false/off}

                          audit=@var{true/on}/@var{false/off}

                          ifelapsed=@var{mins} 
                          expireafter=@var{mins}

     @var{Special OS flags:}
                          flags=@var{BSD flags}


@end smallexample 
@end cartouche

@noindent
An example would be the following:

@smallexample
   any::

      /var/spool/printQ  mode=0775  r=0 o=daemon g=daemon  act=fixdirs

@end smallexample

@noindent
The meaning of these item is sketched out below and becomes clearer on
looking at a number of examples.  Note that, each of the options below
can be written in either upper or lower case and abbreviated by any
unique abbreviation.
@vindex m=
@vindex mode
@vindex l=
@vindex link
@vindex recurse
@vindex r=
@vindex a=
@vindex action
@vindex o=
@vindex owner
@vindex g=
@vindex group
@vindex rxdirs

@table @code

@item @var{/file-object}
This is the only obligatory part of a file action. This may be a
single file or a directory.  If it is a directory then it indicates
where does the file search should begin.  The recursion specifier may
be used to force cfengine to descend into subdirectories in a
controlled fashion, starting from this point, checking files there
also.  The wildcard @code{home} may also be used.  @xref{home
directive}.

A file object is interpreted as a directory if you write it in the
following form: @file{/directory-path/.}. i.e. a trailing dot signifies
a directory. This then becomes the same as the @code{directory} command.
@cindex home wildcard
@cindex Wildcard home
@vindex home

@item mode=@var{modestring}
Specifies what the allowed permissions for files are.  If cfengine finds
that a file's mode is incorrect, the value of the @code{action}
option determines what will be done about it.  The modestring should
consist of either a three digit octal numbers with @samp{+}, @samp{-} or
@samp{=} symbols, or a text string like that used by the command
@code{chmod}.  For instance: @code{mode=u=rwx,og+rx} would mean set the
read/write and execute flags for the user (file owner) and add the
read/execute flags for others and group bits.  An example of the
numerical form might be @code{-002} which would mean that the
read-for-others flag should either not be set or should be unset,
depending on the action you choose.  @code{+2000} would mean that the
setgid flag should be present or set, depending on the action.
@code{+2000,-002} would be a combination of these.  The @samp{=} sign
sets to an absolute value, so @code{=755} would set the file mode to
mode 755.

@item flags=@var{BSD flags}
The free BSD Unices have additional filesystem flags which can be seton
files.  Refer to the BSD @code{chflags} documentation for this.  For
example,

@smallexample

   /tmp/flags.01  mode=0600 owner=0 group=0
                  flags=uappnd,uchg,uunlnk,nodump,opaque,sappnd,schg,sunlnk
                  action=touch      


@end smallexample

@item recurse=@var{number/inf}
This specifier tells cfengine whether or not to recurse into
subdirectories.  If the value is zero, only the named file or directory
is affected.  If the value is 1, it will open at most one level of
subdirectory and affect the files within this scope.  If the value is
@code{inf} then cfengine opens all subdirectories and files beginning
from the specified filename.@xref{Recursion}.

@item owner=@var{owner list}
This is a list of allowed owners, or uids by number, separated by
commas.  For example @code{root,2,3,sysadm}.  In cases where you ask
cfengine to fix the ownership automatically, the owner will be set to
the first recogized owner in the list if and only if it is not one of the named
uids in the list.

@item group=@var{group list}
This is a list of allowed groups, or gids by number, separated by
commas.  For example @code{wheel,2,3,sysadm}.  In cases where you ask
cfengine to fix the ownership automatically, the group will be set to
the first recognized group in the list if and only if it is not one of the named
gids in the list.

@item action=@var{action}
The action is one of the following keywords.

@smallexample
warnall warndirs warnplain
 fixall fixdirs fixplain
touch linkchildren create compress alert
@end smallexample 

@noindent
The upper line results only in warnings being issued.  The actions
beginning `fix' prompt cfengine to fix encountered problems without
bothering the user.  No message is issued unless in verbose mode.  The
special features on the third line will be explained separately.  Alert
is like @code{-print} in the find command, it triggers on the existence
of files which have not been ignored, excluded or filtered. This should
normally be used together @code{filter}, in order to locate files of particular types.


@item include=@var{wildcard/pattern}
You can include this option several times to specify specific patterns
which are to be included in the search. Once you specify one
pattern you exclude all files not matching at least one of the
patterns. The case be useful for restricting a search, or for
modifying the permissions of only certain files.
@cindex Search patterns in @code{files}
@vindex include=
@cindex Pattern matching in file sweeps

@item exclude=@var{wildcard/pattern}
You can include this option several times to specify specific patterns
which are to be excluded from the search. This overrides any patterns
given in the @code{include=} list.
@vindex exclude=
@cindex Excluding files from a file sweep

@item ignore
This works like the global ignore directive but here you may
provide a private list of ignorable directories and files.
Unlike include, exclude this affects the way cfengine parses
directory trees.

@item links=@var{stop/traverse/tidy}
Normally cfengine does not descend into subdirectories which are pointed
to by symbolic links.  If you wish to force it to do so (without using
the @code{-l} command line option) you may give this option the value
@code{true}, or @code{traverse}, or @code{follow}.  To specify no
recursion you set the value @code{false} or @code{stop}.
@cindex Links, traversing in searches
@vindex -l
@cindex -l option
Note that the value set here in the cfengine program @emph{always
overrides} the value set by the @code{-l} command line option, so you
can protect certain actions from this command line option by specifying
a negative value here.  If you specify no value here, the behaviour is
determined by what you specify on the command line.

The value @code{links=tidy} has the same effect as the @samp{-L} command
line option except that here it may be specified per item rather than
globally.  Setting this value causes links which point to non-existent
files to be deleted.
@cindex Deleting stale links
@cindex Links, deleting stale

@noindent
If the warn directive is used (for directories, plain files or both)
then only a warning message is issued if the file being tested does not
match the specification given.  If the fix directives are used then
cfengine does not issue a warning, it simply fixes the value silently.
Non-existent files are created by the @code{touch} command.  A
directory may be touched (created) by writing the filename
@code{/a/b/c/.} with a dot as the last character.  (This may also be
achieved with the @code{directories} directive, @xref{directories}.)

@item define=@var{classlist}
If a file operation results in action being taken to fix a file,
the colon, comma or dot separated list of classes becomes defined.
Warnings do not activate the classes.

@item checksum=@var{md5/sha/best}
If set this option causes cfengine to add a checksum for the named file
to a database. Changes in the value of this checksum are then warned as
a security issue. This should normally only be used to monitor binary
files which one would not expect to change often. Note also that the use
of this option can mean a significant performance penalty. If the value 
@code{best} is used for this option then the best known pair of 
checksum methods are cross-checked for each file. (The best value are
determined by the algorithms supported in the OpenSSL interfaces used
to compile the program).

If @code{ChecksumUpdates} is set, then 
security warning messages are issued only once and the value
in the database is then changed to the new value of the file
automatically i.e. the behaviour is similar to that of setuid root
program detection, @xref{ChecksumPurge}.
Also, @xref{ChecksumUpdates}.
@cindex Message digests
@cindex Hashes of files
@cindex Tripwire functionality

@item xdev
Prevents cfengine from descending into file systems that are not on the
same device as the root of the rescurion path.
@cindex xdev


@item rxdirs
If true (the default) cfengine assumes that a directory that is readable should also
have its execute flag set, allowing users to enter it and perform directory browsing.
If false, cfengine will not make this assumption. Note that if set to false, it will
affect recursive file checks. Thus setting to false with @code{mode=644 recurse=true}
could lead to unintended permissions on directories.
@end table

The default values are @code{mode=+000}, @code{recurse=0},
@code{action=warnall} and any owner or group is acceptable.  The default
for @code{links} is to not traverse links unless the @code{-l} option is
set on the command line.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Recursion, Directory permissions, Syntax, files
@subsection Recursion
@cindex Recursion in files
@cindex Files, recursion

The recursion specifier tells cfengine what to do, starting from
@code{/directory name}.  A value of @code{r=0} means `no recursion' and
any checking is limited only to the named file or directory.  A value of
@code{r=inf} implies unlimited recursion.  Cfengine then descends into
all subdirectories checking or setting the permissions of files until it
`bottoms out' at a plain file.  A value such as @code{R=4} means descend
recursively into subdirectories, but no more than four levels.  This is
a useful safety net in preventing unforeseen accidents.  A recursive
search also bottoms out on device boundaries and symbolic links
(provided the @kbd{-l} option is not used).
@cindex Device boundaries and files
@cindex xdev (File system boundaries)

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Directory permissions, Checksums and change management, Recursion, files
@subsection Directory permissions
@cindex Directory permissions
@cindex Permissions, directories

When you specify the permissions for a whole file tree, using the
recursion specifier it is awkward to have to remember that directories
must be executable.  cfengine will do this for you automatically.  If
you specify that a file tree is to have a read flag set, cfengine will
ensure that the corresponding execute flag is also set for directories
which live in the tree.  So the command

@smallexample
files:

  myclass::

      /dir  mode=a+rw r=inf fixall

@end smallexample 

@noindent
would set all plain files to mode 644 and all directories to 755, that
is read/write for everyone on plain files and read/write/execute for
everyone on directories.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Checksums and change management, home directive, Directory permissions, files
@subsection Checksums and change management
@cindex Checksums
@cindex Hashes

Integrity checks are a good way of detecting tampering
with a system, or simply for monitoring upgrades that happen
as a result of software unrelated to cfengine. The @code{checksum}
option asks cfengine to compute and cache the value of the
cryptographic checksum of the named file. 

@smallexample
files:

  /my/file

   checksum=best
   action=warnall

@end smallexample
The checksum type can be @code{md5}, @code{sha} or @code{best}.
The option best cross checks the best two available algorithms.
At present cfengine is waiting for improvements to the OpenSSL
library supporting sha2 algorithms.

Once a value has been
computed and placed in the database each new computation will be
checked against the old one. Any change will lead to a mismatch
and the following will happen:

@itemize @bullet
@item A warning is printed about the change
@item As of 2.2.8 a class called @code{checksum_alerts} will be defined, indicating
that a change has occurred. This can be used to trigger followup actions. The class
is a persistant class that lasts for 60 minutes.
@item If ChecksumUpdates is set to true, the new value will replace the old in the database
@end itemize

@c .....................................................
@c SUBSECTION
@c .....................................................

@node home directive, Owner and group wildcards, Checksums and change management, files
@subsection @code{home} directive
@cindex home directive
@cindex Files, home wildcard

If you want to check the files of all the users who have their login
areas on the current host, you can use a wildcard directive @code{home}
instead of a directory name.  In this case the file action iterates over
all home directories physically on the current host.  The home
directories are, of course, located by searching for files which match

@smallexample
$(mountpattern)/$(homepattern)
@end smallexample 

@noindent
i.e.  the values which are specified in the @code{control} part of the
program.  For example the following line is a very useful service to
ignorant users.

@smallexample
files:

  any::
 
    home mode=o-w r=inf act=fixall

@end smallexample 

@noindent
It ensures automatically that no user has files which can be written to
by other arbitrary users.

As a corollary to this, you may write something like

@smallexample

  any::

     home/www mode=a+r fixall

@end smallexample

@noindent
to specify a special subdirectory of every users' home directory.  This
statement would check that all of the files in users' world wide web
directories were readable for everyone.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Owner and group wildcards, Files linkchildren, home directive, files
@subsection Owner and group wildcards
@cindex Ownership of files
@cindex Files, ownership

If you do not want to explicitly state the owner or group of a file you
may simply omit the group or owner options.

@smallexample

  /@var{file-object} m=0664 r=inf

@end smallexample 
This example generate a warning if any files under the named directory
do not have permission read/write for all users.

@c .....................................................
@c SUBSECTION
@c .....................................................
@node Files linkchildren, touch, Owner and group wildcards, files
@subsection Files linkchildren
@vindex linkchildren
@cindex Linkchildren

The @code{linkchildren} facility is almost identical to that already
described under @code{links}.  @xref{Link Children}.  The only
difference here is that the ownership and permissions on the links are
set all in one operation.  For example:

@smallexample
@var{myclass}::

   /local/lib/emacs m=0770 o=me g=mygroup act=linkchildren

@end smallexample 

@c .....................................................
@c SUBSECTION
@c .....................................................
@node touch, create, Files linkchildren, files
@subsection touch
@vindex touch
@cindex Touching files

The @code{touch} facility creates a new file with the
specified permissions and ownership, or corrects the
permissions and ownership of an existing file, in addition
to updating the time stamps.

@smallexample
@var{myclass}::

   /@var{newfile} mode=0644 action=touch

@end smallexample 

@c .....................................................
@c SUBSECTION
@c .....................................................
@node create,  , touch, files
@subsection create
@vindex create
@cindex Creating files

This is like @code{touch} except that an existing
file's time stamps, permissions and ownership will not be modified
if the file already exists. If the file does not exist, the
attributes are set to the values specified, or to the default
values of @code{0644}.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node filters, groups, files, Cfagent reference
@section filters
@vindex filter
@cindex  Selecting files in searches
@cindex Searching, advanced

A filter is a way of selecting or pruning during a search over
files or processes. Since filter rules could apply to several objects, cfengine
allows you to define filter conditions as separate objects to be
applied in different contexts.

Filter objects can be used in @code{copy}, @code{editfiles},
@code{files}, @code{tidy} and @code{processes}. In most cases one
writes

@smallexample
.. filter=<i>filteralias</i>
@end smallexample
in the appropriate command. The exception is @code{editfiles}, where the syntax
is 

@smallexample
@{
..
Filter "filteralias"
..
@}
@end smallexample
Example:

@smallexample

files:

 /tmp filter=testfilteralias action=alert r=inf

@end smallexample

Filters are defined in a separate section. Filters for files
and processes are defined together. They differ only in the
criteria they contain. Here is are examples of file filters:

@smallexample
Filters:

  @{ filteralias1

  Owner:     "mark|cell|motd"
  Group:     "ecg|mark"
  Mode:      "700"

  FromCtime: "date(2000,1,1,0,0,0)"    # absolute date
  ToCtime:   "now"

  FromMtime: "tminus(1,0,0,2,30,0)"    # relative "ago" from now
  ToMtime:   "inf"                     # end of time

  FromAtime: "date(1997,2,22,0,0,0)"
  ToAtime:   "inf"

  FromSize:  "10000"                   # File size interval
  ToSize:    "10mb"

  ExecRegex: "/usr/bin/file $(this) (.*ascii.*)"# Result from "files" command 

  Type:      "dir|link"                # reg|link|dir|socket|fifo|door|char|block

  NameRegex: ".*.asc"                  # regex matching file name

  IsSymLinkTo: "/dev/null"             # True if file is a link to object name regex

  Result:    "Type"                    # Result which shouldbe returned
                                       
  @}

 #########################################

  @{ testfilteralias2

  ExecProgram: "/bin/ls $(this)"       # True if the program returns true. $(this) is the current object
  @}

 #########################################

  @{ testfilteralias3

  Owner: "mark"
  @}
@end smallexample


Filters are evaluated like classes. In fact, the filtering works by evaluating
the class attributes for each file. 

File filters:

@table @code 
@item Owner:
 and Group can use numerical id's or
names, or @code{``none''} for users or groups which are undefined in
the system passwd/group file.

@item
Mode: applies only to file objects. It shares syntax with
the @code{mode=} strings in the files command. This test returns
true if the bits which are specified as `should be set' are indeed
set, and those which are specified as `should not be set' are not set.

@item Atime:,Ctime:,Mtime: 
apply only to file objects.
These specify ranges From and To. If the file's time stamps
lie in the specified range, this returns true. Times are
specfied by a six component vector

@smallexample
(year,month,day,hour,minutes,seconds)
@end smallexample
This may be evaluated as two functions: date() or tminus()
which give absolute times and times relative to the current time respectively.
In addition, the words now and inf may be used.
e.g.

@smallexample
  FromCtime: "date(2000,1,1,0,0,0)"   # absolute date
  ToCtime:   "now"

  FromMtime: "tminus(1,0,0,2,30,0)"     # relative "ago" from now
  ToMtime:   "inf"                     # end of time
@end smallexample


@item Type:
applies only to file objects may be a list of file types
which are to be matched. The list should be separated by the OR symbol
`|', since these types are mutually exclusive. The possible values are
currently

@smallexample
file|reg|link|dir|socket|fifo|door|char|block
@end smallexample
Note that @code{file} and @code{reg} are synonymous.
@item ExecRegex: 
matches the test string against the output of the specified command.
@item NameRegex: 
matches the name of the file with a regular expression.
@item IsSymLinkTo: 
applies only when the file object $(this) is a symbolic link. It is true
if the regular expression matches the contents of the link.
@item ExecProgram: 
matches if the command returns successfully (with return code 0).
Note that this feature introduces an implicit dependency on the command being
called. This might be exploitable as a security weakness by advanced intruders.
@item Result: 
specifies the way in which the above elements are combined
into a single filter.
@end table

Process filters:

@table @code
@item Owner
 process owner UID (quoted regex)
@item PID:
 process ID (quoted regex)
@item PPID:
 parent process ID (quoted regex)
@item PGID:
 process group ID (quoted regex)
@item RSize:
 resident size (quoted regex)
@item VSize:
 virtual memory size (quoted regex)
@item Status:
 status (quoted regex)
@item Command:
 CMD or COMMAND fields (quoted regex)
@item (From/To)TTime:
 Total elasped time in TIME field (accumulated time)
@item (From/To)STime: 
Starting time for process in STIME or START field (accumulated time)
@item TTY: 
terminal type, or none (quoted regex)
@item Priority: 
PRI or NI field (quoted regex)
@item Threads: 
NLWP field for SVR4 (quoted regex)
@item Result: 
logical combination of above returned by filter (quoted regex)
@end table
Examples: processes started between 18th Nov 2000 and now.

@smallexample
  @{ filteralias

  FromSTime: "date(2000,11,18,0,0,0)"
  ToSTime:   "now"
  @}
@end smallexample
All processes which have accumulated between 1 and 20 hours of CPU time.

@smallexample
  @{ filteralias

  FromTTime:  "accumulated(0,0,0,1,0,0)"
  ToTTime:    "accumulated(0,0,0,20,0,0)"
  @}
@end smallexample

@menu
* Complete filter examples::    
@end menu

@node Complete filter examples,  , filters, filters
@subsection Complete filter examples

Here is an example filter to search for all files which are either directories or links,
or any kind of file owned by mark, in group cfengine.

@smallexample

control:

 actionsequence = ( files )

files:
 
 /tmp       filter=testfilteralias action=alert r=inf
 /cfengine  filter=testfilteralias action=fixall r=inf mode=644

filters:

  @{ testfilteralias

  Owner:     "mark"
  Group:     "cfengine"
  Type:      "dir|link"

  Result:    "Type|(Owner.Group)"  # Both owner AND group required correct
  @}

@end smallexample
Find all ELF executables using data from the Unix @code{file} command.
Caution, this takes a long time if used indescriminately.

@smallexample

control:

 actionsequence = ( files )

files:
 
 /tmp       filter=testfilteralias action=alert r=inf
 /cfengine  filter=testfilteralias action=fixall r=inf mode=644

filters:

  @{ testfilteralias

  ExecRegex: "/bin/file (.*ELF.*)"

  Result: "ExecRegex"
  @}
@end smallexample
Here is an example which warns of any process coupled to a terminal
started in November:

@smallexample
control:

 actionsequence = ( processes )

filters:
 
  @{ filteralias
  FromSTime: "date(2000,11,0,0,0,0)"
  ToSTime:   "date(2000,11,30,0,0,0)"
  TTY: ".*pt.*"
  Result: "TTY.STime"
  @}

processes:

 "." filter=filteralias action=warn

@end smallexample


@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node groups, homeservers, filters, Cfagent reference
@section groups/classes
@vindex groups
@cindex  Defining groups
@cindex Groups, defining

The @code{groups} action (equivalently referred to as @code{classes} as
of version 1.4.0) is used to define classes which stand for groups of
hosts.  If you use the NIS (network information service) facility for
defining @emph{netgroups} then this idea will already be familiar to you
and you can probably use your already-defined netgroups in cfengine.
@cindex @code{groups}
@cindex @code{classes}

To define a group, you simply make a list and assign it a name.  Here is
an example of the syntax:

@smallexample

groups:

  ANDed_class::
 
    science = ( saga tor odin )

    packages = ( saga ) 

    AllHomeServers   = ( saga )
    AllBinaryServers = ( saga )

    OIH_servers = ( saga )
    OIH_clients = ( tor odin )

    notthis = ( !this )

    ip_in_range = ( IPRange(129.0.0.1-15) )  # host is in ip address range
    ip_in_range = ( IPRange(129.0.0.1/24) )  # host is in ip address range (CIDR notation)

    compute_nodes = ( HostRange(cpu-,1-32) ) # host name in the cpu-01 through cpu-32 range

@end smallexample 
@cindex CIDR
@cindex Classless IP addresses

@noindent
To include a list of hosts from a NIS netgroup, you use the @samp{+} symbol, or
the @samp{+@@} construction.  For example:

@cindex Netgroups
@cindex NIS, netgroup support
@vindex +

@w{}
@smallexample

groups:
 
   science = ( +science-allhosts )

   physics = ( +physics-allhosts )

   physics_theory = ( +@@physics-theory-sun4 dirac feynman schwinger )

@end smallexample 

@noindent
Using an enormous netgroup does not use up any space.  A group
declaration results in the storage of only the class name regardless of
how many hosts are in the list.  The rule is that the left hand side of
the assignment becomes defined (true) if the list on the right hand side
includes the host which is parsing the file --- i.e.  @code{$(host)}.

In some cases your netgroups will not correspond exactly to the list you
want, but it might be more convenient to use a netgroup @emph{except}
for certain hosts.  You can `undefine' or remove hosts from the netgroup
list by using the minus `-' symbol.  For example:

@cindex Removing entries from netgroups
@cindex Negating entries from netgroups
@cindex Netgroups, negating entries

@w{}
@smallexample

group = ( +mynetgroup -specialhost -otherhost )

@end smallexample 

@noindent
which means, of course, all hosts in netgroup @code{mynetgroup} except
for @code{specialhost} and @code{otherhost}.  Finally, you may also
subtract two netgroups in the following manner.

@smallexample
group = ( +bignetgroup -smallnetgroup )
@end smallexample 

@noindent
The `minus' command effectively eliminates its members from
@code{bignetgroup} if they exist within that group.  If none of the
hosts in @code{smallnetgroup} exist in @code{bignetgroup} then the
command has no effect.

@cindex Group dependencies
@cindex Class dependencies
@cindex Dependencies
Groups may contain previously defined cfengine groups too. This
allows one class to inherit the attributes of another class, for instance:

@smallexample

  AllSun4Hosts   = ( sonny sunny solar stella )
  AllUltrixHosts = ( ully olly wally golly )

  AllBSD = ( AllSun4Hosts AllUltrixHosts )

@end smallexample

@noindent
The classes on the right hand side are effectively ORed together into
the left hand side.  This enables complex classes to be constructed from
several other basic classes, e.g.

@smallexample

  SpecialTimes = ( Hr00 Monday Day1 )

@end smallexample

@noindent
which evaluates to true every day when it between 00:00 hours and 00:59,
all day Monday and all day on the first day of every month.

If you apply a class predicate before a definition then the result
is effectively the AND of the classes:

@smallexample

 Hr00::

  SpecialTime = ( Monday Tuesday )

@end smallexample
defines @code{SpecialTime} at Hr00 on Monday or Tuesday.

@cindex Shell command to decide class
@cindex Class decided by shell command
Finally, you can define groups (strictly classes) by the result of a shell
command. A shell command or program is deemed to be `true' if it
exits with a status of zero, i.e. it calls @code{exit(0)}. Any other
value is taken to be false. You can include shell commands as the members
of groups in order to define classes based on the outcomes of your
own scripts by enclosing the script in single or double quotes:

@smallexample

   have_cc = ( '/bin/test -f /usr/ucb/cc' )

@end smallexample

@noindent
The class @code{have_cc} will then be defined if the shell command returns
true. Of course, you can put any script or program in the single quotes as
long as they adhere to the convention that zero exit status means true.
If you have several members which are shell commands, then the effect is
to make the class the logical OR of the scripts' results.



@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node homeservers, ignore, groups, Cfagent reference
@section homeservers

@cindex Home servers, defining
@cindex Defining a home server
@vindex homeservers

The @code{homeservers} declaration need only be used if you are using
cfengine's model for mounting NFS filesystems.  This declaration informs
hosts of which other hosts on the network possess filesystems containing
home directories (login areas) which client hosts should mount.

A sample homeserver declaration looks like this:

@smallexample

homeservers:

   Physics::  einstein 
   Math::     riemann euler

@end smallexample 

@noindent
The meaning of this declaration is the following.  Any host which finds
itself to be a member of the classes on the left hand side of the
assignment need to mount all home directory resources from the hosts on
the right hand side of the assignment.  The pattern variable
@code{homepattern} is used to determine which resources are home
directories in the list of @code{mountables}.  @xref{mountables}.

Let us consider an example in which @code{homepattern} is set to the
wildcard value @samp{home?} and the mountables list is given by

@smallexample
mountables:
   
   einstein:/mysite/einstein/home1
   einstein:/mysite/einstein/home2  mountoptions=soft,bg,intr,rsize=8192,wsize=8192
   riemann:/mysite/riemann/local    readonly=true
   euler:/mysite/euler/home1
  
@end smallexample 
@vindex mountables
@cindex Mountable resources, defining

Any host in the group @code{Physics} would now want to mount all home
directories from the host @code{einstein}.  There are two of these.
Both the filesystems listed for @code{einstein} match the
@code{homepattern} variable since they end in @samp{home?}.  cfengine
would therefore take this to mean that all hosts in @code{Physics}
should mount both of these filesystems.

Hosts in @code{Math}, on the other hand, should mount only
homedirectories from the hosts @code{riemann} and @code{euler}.  There
is only a single filesystem on @code{riemann} and it does not match
@code{homepattern}, so it is not mounted.  On @code{euler} there is a
match, so this filesystem will be added to the appropriate hosts.

@emph{Cfengine picks out home directory resources from the
@code{mountables} list by trying to match the @code{homepattern}
variable, starting from the end of the directory name.  You do not
therefore have to use the designation @code{/site/host/home?}  but this
is a simple choice and is highly recommended.}


@page


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node ignore, import, homeservers, Cfagent reference
@section ignore

When you specify a recursive search as part of a @code{files},
@code{tidy} or @code{copy} action, you would sometimes like to exclude
certain directories from the list of sub directories.  In most cases you
will want to do this on a per-command basis (see the pages for these
actions separately), but you can also make a global ignore list.  This
can be accomplished by adding the directory to the ignore-list.  The syntax
is

@cartouche

@w{}
@smallexample

  ignore:

     @var{wildcards/directories/filenames}

@end smallexample
@end cartouche

For example:
@cindex ignore command

@w{}
@smallexample

ignore:

   any::

      #
      # Prevent tidying .X11 directories in /tmp where
      # window managers write semaphores
      #

      .X11

      #
      # Don't tidy emacs locks
      #

      !*
      /local/lib/gnu/emacs/lock/
      /local/tmp
      /local/bin/top
      /local/lib/tex/fonts
      /local/etc
      /local/www
      /local/mutils/etc/finger.log


@end smallexample 

@noindent
None of the above directories will be checked or entered during
recursive descents unless a specific command is initiated to search
those directories with their names as the top of the search tree.
@cindex .X11 directory

A handy tip if you are tidying @file{/tmp} recursively is to include the
directory @file{.X11} here.  This directory is used by the X-windows
system and deleting it while a window manager has an open session can
cause the user some trouble.

Ignore refers to all recursive searches in tidy, files, copy and links.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node import, interfaces, ignore, Cfagent reference
@section import
@cindex Importing files
@cindex Several files
@cindex Files, importing
@cindex Files, breaking up into several
@vindex import

To break up a large configuration file into smaller files you can use
the include directive.  This conditionally reads in files if the class
on the left hand side of the assignment matches the host parsing the
file.  This enables also a variety of cfengine configuration scripts to
read in a standard set of default settings.  The syntax of the statement
is:

@smallexample

import:       

   any::
      
      cf.global_classes
 

   linux::
    
      cf.linux_classes
     

@end smallexample 

Note that, if you define variables in an imported file they will not be
defined for operations in their parent files. This because cfengine reads in all the
import files after the main file has been parsed---not at the place where you
call import in your script. This means that variables or macros defined in
imported files are only defined after the main program. Variables from earlier
files are inherited by later includes, but not @emph{vice-versa}.

@cindex Variables in import files
@cindex Import files, variables in


@page
@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node interfaces, links, import, Cfagent reference
@section interfaces

@cindex Network interfaces, several
@cindex Dual homed hosts
@vindex interface configuration


@cartouche

@w{}
@smallexample

 interfaces:

   @var{classes}::

     @var{interfacename} netmask=@var{netmask} broadcast=@var{broadcast}

@end smallexample
@end cartouche

If you have more than one network interface, or you do not wish to use the
default interface name, this section may be used to define further
interfaces to be checked. This feature can replace the older method
of setting netmask and broadcast address in @code{control:}. If the @code{netmask}
variable is not set, cfengine ignores the default interface configuration.
Example:

@smallexample

  interfaces:

    "le1" netmask=255.255.255.0 broadcast=ones
    "le2" netmask=255.255.255.0 broadcast=ones

@end smallexample

@page


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node links, mailserver, interfaces, Cfagent reference
@section links

@cindex Making links
@cindex Links, making
@vindex links


The symbolic links function is one of the greatest plusses in cfengine
as a system administration tool.  It allows you to do two things: check
single links for correctness and consistency (or make them if they do
not exist), and check or make links to every file in a designated
directory.  This latter feature is called multiple linking or linking
children.  The @code{linkchildren} feature is also available from the
@code{files} action  @xref{files}. The syntax of a link item is:

@cartouche

@w{}
@smallexample

  @var{from-link} ->[!] @var{to-object} 
 @var{or}
  @var{from-link} +>[!] @var{to-object} 

            type=@b{symbolic/absolute/abs}/@var{hard/relative/rel}
            copy=@var{pattern}
            recurse=@var{number/inf/}@b{0} 
            copytype=@var{checksum/}@b{ctime}
            include=@var{pattern}
            exclude=@var{pattern}
            ignore=@var{pattern}
            action=@var{silent}
            deadlinks=@b{kill}/@var{force}
            define=@var{classlist}
            nofile=@b{kill}/@var{force}
            syslog=@var{true/on}/@var{false/off}

            inform=@var{true/on}/@var{false/off} 
            audit=@var{true/on}/@var{false/off}

            ifelapsed=@var{mins} 
            expireafter=@var{mins}
@end smallexample
@end cartouche

@noindent
@emph{The special variable @code{$(binserver)} can be used in @code{links}.}

@c .....................................................
@c SUBSECTION
@c .....................................................

@menu
* Single links::                
* Multiple Links::              
* Link Children::               
* Relative and absolute links::  
* Hard links::                  
@end menu

@node Single links, Multiple Links, links, links
@subsection Single links
@cindex Single links
@cindex Links, single

To define a single link, you create an entry of the following
form:

@smallexample

links:

  @var{class}::

     @var{linkname} -> @var{object_to_link_to}
     @var{linkname} -> ./@var{relative_link}
     @var{linkname} -> ../@var{relative_link}

@end smallexample 

@noindent
If links exists and point to their intended destinations then no
action is taken.  If a link exists but points incorrectly then a
warning is issued, unless the pling operator @samp{!} is given, in
which case the correct value is forced.  
If the link exists and points to a file which does
not exist a warning is issued unless the command line option @code{-L}
is used, in which case the link is deleted. 
@cindex @code{-L} option
@vindex -L

Here is an example of some valid link statements.

@smallexample

links:

  Physics.sun4::
 
   /usr/local       -> /$(site)/$(host)/local
   /home            -> /$(site)/$(host)/u1
   /etc/sendmail.cf -> /usr/local/mail/etc/global-sendmail.cf

   /usr/lib/sendmail ->! /local/lib/sendmail 

@end smallexample 

@noindent
cfengine makes any directories which are required leading up to the link
name on the left hand side of the arrow automatically. In the last
example the `pling' forces cfengine to make the link even if a file for
link exists previously. Plain files are saved by appending
@file{.cfsaved} to the filename, or by moving to a repository, whereas
old links are removed.  The same effect can be enforced globally using
the @code{-E} option, but only if the program is run interactively. (In
this case a prompt is issued to make sure that you wish to use such a
big hammer on your system!)

The link operation accepts a number of parameters

@table @code

@item type=@var{hard/relative/absolute}
If the link type is hard, a hard link is created @xref{Hard links}.
Symbolic links may specify two special types. If @code{relative}
is selected, and the `to' object is an absolute path name,
the link name will be rewritten as a pathname relative
to the source file, using @samp{.} and @samp{..} to move relative
to the current directory. For instance, a link from @file{/usr/local/file}
to @file{/usr/file} would be linked as @file{./../file}.
If the `to' object is already relative,
this has no effect. 

If @code{absolute} is specified, cfengine
will try to resolve the true path location of the `to' object,
expanding any symbolic links or dots in the path name, up to
a maximum of four levels of symbolic links. 

@cindex Relative links
@cindex Symbolic links, relative
@cindex Links, absolute
@cindex Absolute links
@cindex Symbolic links, absolute
@cindex Links, absolute

@item copy=@var{pattern}
This option can be repeated any number of times to build up a list of
filenames or wildcards which are to be copied rather than linked
symbolically. The copy is made on an age-comparison basis. A global
variable may also be set to invoke this feature @xref{copylinks}.
Directories cannot be copied in this way.

@item copytype=@var{checksum/ctime}
This specifies the basis for deciding whether to update a file
which is to be copied instead of linked @xref{copy}.

@item nofile=@b{kill}/@var{force}
This decides what happens to links which point to non-existent
files. The default action is to remove such links, or refuse to
create them. By setting the @var{force} option you can force
cfengine to make symbolic links to files which do not exist.
This is useful for setting up links to filesystems which
are not permanently mounted.
@cindex Links, removing dead
@cindex Links, forcing for non-existent files

@item exclude=@var{pattern}
This option can be repeated any number of times to build up a list of
filenames or wildcards which are to be excluded from the linking
process. A global variable may also be set to invoke this feature 
@xref{excludelinks}.

@item ignore
This works like the global ignore directive but here you may
provide a private list of ignorable directories and files.
Unlike include, exclude this affects the way cfengine parses
directory trees.

@item recurse=@var{number/}inf
This option can only be used with multiple link operations @xref{Multiple Links}.
If this option is specified, cfengine links only non-directory
objects. Directories are instead created and links within those
directories are also created. The value of this option specifies the
maximum number of levels to which cfengine should recursively descend a
link tree. @code{inf} means infinite recursion. Cfengine also ignores
files and directories in the ignore list @xref{ignore}.

@item define=@var{classlist}
If a link is created or replaced, the colon, comma or dot separated
list of classes becomes defined.

@end table

@cindex Binary servers and links
@cindex Links and binary servers
@vindex binserver
The final feature of the links facility is connected to the use of the
cfengine model for mounting NFS filesystems.  In particular it concerns
the variable @code{$(binserver)}.  The easiest way to understand this
feature is to illustrate a couple of examples.  Consider the following:

@smallexample
links:

   any::

      /local -> /$@{site@}/$@{binserver@}/local

@end smallexample 

@noindent
The result of this command is quite different depending on which host is
executing it.  The variable @code{$(site)} clearly has a fixed value,
but the variable @code{$(binserver)} might expand to any valid binary
server for the host executing the program.  @xref{binservers}.  The
procedure cfengine adopts is to go through its list of mountables,
keeping only those mountable resources which belong to defined binary
servers for the current host.  It then attempts to match a filesystem by
substituting @code{$(binserver)} with each of its valid binservers in
turn and it matches the first one binary server which yields an existing
file.

@cindex Binary servers, priority
Note that every host is a binary server for itself, so that the value of
@code{$(binserver)} which has absolute priority is alway the same as the
value of @code{$(host)}.  This ensures that the link will always be made
to a local filesystem if the rules of the model are upheld.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Multiple Links, Link Children, Single links, links
@subsection Multiple Links
@cindex Multiple links
@cindex Links, multiple

With the link symbol @code{+>}, you opt to link all of the files in a
directory to corresponding files in another directory.  This procedure is
sometimes useful for installing software.  In the example

@smallexample

links:

  myclass::

     /usr/local/bin +>  /usr/local/lib/perl/bin
     /opt           +>! /local

@end smallexample 

@noindent
every file in the directory @code{/usr/local/lib/perl/bin} is linked
symbolically to a corresponding file in @code{/usr/local/bin}. The
`pling' character forces cfengine to replace old links or plain files
already existing. Old links are removed, whereas old files are saved
by appending @file{.cfsaved} to the filename @xref{repository}.
@cindex @file{.cfsaved} files

Each time cfengine runs it goes through all of the files in the
directory concerned and checks the appropriate link accordingly.  If new
files appear, new links will be added.  If a file disappears but the
link to it remains, a warning will be issued, unless the @code{-L}
command line option is used, in which case the link is deleted.


@c .....................................................
@c SUBSECTION
@c .....................................................

@node Link Children, Relative and absolute links, Multiple Links, links
@subsection Link Children
@cindex Linkchildren
@vindex linkchildren

The linkchildren directive is a closely related to the cfengine model
for NFS filesystems.  It is a way of making links which embodies a
rudimentary kind of `intelligence'.

@cindex Binary servers and links
@cindex Links and binary servers
@vindex binserver
Consider the following:

@smallexample
links:

   any::

      /usr/local/lib/emacs +> linkchildren

@end smallexample 

@noindent
The word @code{linkchildren} automatically tells cfengine that it should
look for an appropriate file to link to on a binary server for the
current host.  The exact meaning of the above statement is as follows.
cfengine begins searching though the list of mountable resources,
discarding any filesystems which do not belong to valid binary servers.
It looks for a filesystem ending in `emacs' (the last link of the left
hand side).  If all is well, these file systems are already mounted and
they can be searched.  If no resource is found ending in `emacs', we go
to the next link @code{lib} and look for a filesystem ending in `lib'.
If this is not found we go to @code{local} and so on.  When a match is
made, cfengine then tries to locate the file by checking whether it
exists relative to the matched filesystem.  For example, suppose `local'
matched with @code{host:/site/host/local}.  It would then try to locate
@code{host:/site/host/local/lib/emacs} and link all of the children
therein to the local file directory @code{/usr/local/lib/emacs}.

@cindex Making use of local disk space
@cindex Local disk space, make use of
Here is another example which makes reference to the cfengine model for
mounting NFS filesystems.  Suppose you have a host with some spare disk
space.  You want to mount @code{/usr/local} from the binary architecture
server, but you also want to use the disk you have locally.  The
following lines

@smallexample
links:

   electron::

      /$(site)/electron/local +> linkchildren

   any::

      /usr/local              -> /$(site)/$(binserver)/local

@end smallexample 

@noindent
have the effect of creating a directory @code{/$(site)/electron/local}
and filling it with links to all of the files and directories on the
binary server's mounted filesystem.  It results in an exact copy (by
linkage) on the local disk, but does not use up your local disk space.
The space you have remaining could, for example, be used for software
with a special license for that host.  The second link links
@code{/usr/local} to the `nearest' binary server.  But the nearest
binary server is always @code{$(host)} which means this evaluates to a
file which now exists because of the first command, so on the host
`electron' the directory @code{/usr/local} ends up being a link to
@code{/$(site)/electron/local} which is full of links to the binary
server.

If you've caught your breath after that mouthful you probably have mixed
feelings about creating a bunch of links in this way.  What happens if
the files they point to are removed? Then you are left with a lot of
useless links.  Actually this is no problem for cfengine, since you can
ask cfengine to simply remove links which point to non-existent files
@xref{files}.  Nevertheless, this feature clearly requires some caution
and is mainly a spice for advanced users of the cfengine model.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Relative and absolute links, Hard links, Link Children, links
@subsection Relative and absolute links

When specifying symbolic linking, you can ask cfengine
to change the link type to be either relative to the
source or to be an absolute path. What this means is the
following. Consider the following link:

@smallexample

   /var/tmp/cfengine -> /local/cfengine

@end smallexample

@noindent
If we add the option @code{type=relative}, then instead
of creating a link which points to @file{/local/cfengine},
the link is created pointing to the location

@smallexample
  ./../../local/cfengine
@end smallexample

@noindent
In other words, the link is relative to the calling
directory @file{/var/tmp}.

If a link is specified as being absolute with the option
@code{type=absolute}, then cfengine attempts to resolve
to value of the link so as to be the true path of the
target. If the target name contains a symbolic link, then
this is expanded as far as possible to give the true
path to the file. For example, if @file{/local} is
really a link to @file{/site/myhost/local} then the link
would point to @file{/site/myhost/local/cfengine}.

@c .....................................................
@c SUBSECTION
@c .....................................................

@node Hard links,  , Relative and absolute links, links
@subsection Hard Links
@cindex Hardlinks
@vindex type=

Cfengine will also allow you to create hard links to regular files.  A
hard link is in every way identical to the original file, it merely has
a different name (technically, it is a duplicate inode). To create a
hard link you use the link-option @code{type=hard}. For example:

@smallexample

links:

   /@var{directory}/@var{newname} -> /@var{directory}/@var{othername} type=hard

@end smallexample

@noindent
Cfengine will not create hard links to directories or other special files.
This is always a slightly dubious practice and is best avoided anyway.
POSIX says that the hard link can be on a different device to the file
it points to, but both BSD and System V restrict hard links to be on
the same device as their predecessors. Cfengine has no policy on this,
but---in the theoretical case in which the hard link and the predecessor
were on different file systems---it becomes near impossible to determine
with certainly between a hard link and a very similar regular file, and thus
cfengine issues a warning in verbose mode about this eventuality.
Provided both link and predecessor are on the same filesystem cfengine
determines the status of hard links by comparing the device and inode
numbers of the file pointed to.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node mailserver, methods, links, Cfagent reference
@section mailserver
@cindex Mail server, defining
@cindex Defining a mail server
@vindex mailserver

The @code{mailserver} declaration need only be used if you are using
cfengine's model for mounting NFS filesystems.  This declaration informs
hosts of which NFS filesystem contains mail for its users.  All hosts
apart from the mail-host itself must then mount the mail spool directory
across the network.  The declaration looks like this:

@smallexample

mailserver:

   @var{class}::      mailhost:/var/spool/mail 

@end smallexample 

@noindent
The result of the @code{mailcheck} command in the action-sequence is now
to mount the filesystem @code{/var/spool/mail} on the host
@code{mailhost}.  This action is carried out on any machine which does
not already have that filesystem mounted.
@vindex mailcheck

The mail spool directory is mounted, by default, onto the official mail
spool directory for the system which is parsing the program.  In other
words, on an HPUX system, the spool directory is mounted on
@code{/usr/mail} by default, whereas on a Sun system it would be mounted
on @code{/var/spool/mail}.  The default location can be changed by using
the resource file.  @xref{cfrc resource file}.


@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node methods, miscmounts, mailserver, Cfagent reference
@section methods
@cindex Methods
@cindex Private modules
@vindex methods

From version 2.1.0, cfagent provides for the execution of closed
functions or "methods".  Methods are similar to the old idea of modules,
but they are implemented in a way that allows collaboration between
different hosts within a network, using a common standard. Methods must
be cfengine programs however, wheras the module interface can be written
in any script language.

@emph{Methods are designed to offer a firewall-like proxy interface for remote
method execution. We can call methods a form of `voluntary RPC', in which
hosts execute methods for one another on a purely voluntary basis. This
builds in anti-spamming protection. The principle used is that hosts
should be immune to Denial of Service attacks; they should
only be able to disadvanatge themselves with the attempt.}

(Remote method execution was not implemented until version 2.1.3. It is still
considered experimental and should be tested carefully for
production environments with at least version 2.2.2.
List expansion is particularly fragile in cfengine 2. This problem cannot be
resolved in version 2, so this should not be reported as a bug.
)


@cindex Warning remote methods
@cindex Methods, remote caution

Methods allow you to call an independent cfengine program, pass it
arguments and classes, and collect the results for use in your main
program. It thus introduces parent-child semantics into cfengine
"imports". A method is more than an import.  (Import is analagous to a C
#include, while a method is like a C function.)  Communication is peer
to peer, by mutual consent. There is no "method server" that executes
methods on remote hosts. Hosts exchange information by invitation
only. This is an unreliable service (in the sense of UDP).

The order of method exeuction is not guaranteed. This results from the
decoupling between client request and service provision.

@cartouche

@smallexample

  methods:

     @var{class}::


      @var{function_name}(@var{parameters or none})

      action=@file{filename}                

      sendclasses=@var{comma separated class list}

      returnvars=@var{comma separated variable list or void}
      returnclasses=@var{comma separated class list}

      server=@var{ip-host/localhost/none}

      forcereplyto=@var{ip address}

      owner=@var{setuid}
      group=@var{setgid}
      chdir=@var{cd for child}
      chroot=@var{sandbox directory}

@end smallexample
@end cartouche
Most of these functions will be familiar from other cfengine
commands. Some special ones are noted below:

@table @code
@item action
The name of the method file that should be defined in the modules
directory of the server host.
@item forcereplyto
Sometimes nameservice problems (especially with remote devices) can lead
to confusion about where a method should be sent. The caller can
therefore declare to the server which address it wants the reply to be
marked for.
@item returnvars
Returns the values of the variables to the parent process. This acts as
an access control list for variable names transmitted by the child
process. The names returned by the child must match this list.
@item returnclasses
Returns the classes to the parent process, if and only if they are
defined at the end of the current method. This acts as an access control
list for class names transmitted by the child process. The names
returned by the child must match this list.

@item sendclasses
Transmits the current status of the named classes to the child
process. In other words, if the listed classes are defined, they become
defined in the child process, else they remain undefined. The class may
still be defined in the child by independent local definitions.
@end table

If the server is set to @code{localhost}, the method will be
evaluated on the local machine. If the server is set of @code{none},
the method will not be executed at all.
@cindex none in server
@vindex none

The function arguments may not be empty, but a null value can be
transmitted with a dummy value, e.g. @code{Function(null)} or
@code{function(void)}.  Here is an example method call.

@smallexample

 # cfagent.conf

control:

   actionsequence = ( methods )

#################################################

methods:

 any::

   SimpleMethod(null)

      action=cf.simple
      returnvars=null
      returnclasses=null
      server=localhost


@end smallexample
With method file (located in the ModulesDirectory),

@smallexample

 # cf.simple

  control:

    MethodName       = ( SimpleMethod )
    MethodParameters = ( null )
    actionsequence   = ( timezone )


  classes:

     dummy = ( any )

####################################################

alerts:

 dummy::

  "This simple method does nothing"

  ReturnVariables(void)
  ReturnClasses(void)

@end smallexample
On executing this example, the output is:
@example
nexus$ ./cfagent -f ./cftest
cfengine:myhost:SimpleMethod: cfengine:nexus: This simple method does nothing

@end example

If the server name is a wildcard, e.g. @code{*} then this acts as a multicast or broadcast.

@c ...........................................
@c SUBSECTION
@c ...........................................

@menu
* localhost examples::          
* remotehost examples::         
@end menu

@node localhost examples, remotehost examples, methods, methods
@subsection Localhost examples


The following example
collects the tar file, unpacks it,
configures and compiles it, then tidies its files.

@smallexample
####################################################
#
# This is a cfengine file that calls a method.
# It should be in the usual place for cfinputs
#
####################################################
 
control:

   actionsequence = ( methods )

#####################################################

methods:

   InstallTar(cfengine-2.1.0b7,/local/gnu)

      action=cf.install
      returnvars=null
      returnclasses=null
      server=localhost

@end smallexample
We must install the method in the trusted modules directory
(normally /var/cfengine/modules or WORKDIR/modules).

@smallexample
####################################################
#
# This is an example method file, that needs to be
# in the module directory /var/cfengine/modules
# since this is the trusted directory
#
# e.g. InstallFromTar(cfengine-2.1.0,/usr/local/gnu)
#
####################################################

control:


 MethodName       = ( InstallTar )
 MethodParameters = ( filename gnuprefix )
 
 path = ( /usr/local/gnu/bin )


 TrustedWorkDir = ( /tmp )

 TrustedSources = ( /iu/nexus/ud/mark/tmp )
 TrustedSourceServer = ( localhost )

 actionsequence = ( copy editfiles shellcommands tidy )

####################################################

classes:

  Force = ( any )

####################################################

copy:

 $(TrustedSources)/$(filename).tar.gz 

    dest=$(TrustedWorkDir)/$(filename).tar.gz 
    server=$(TrustedSourceServer)

####################################################

shellcommands:

 "$(path)/tar zxf $(filename).tar.gz" 

     chdir=$(TrustedWorkDir)

 "$(TrustedWorkDir)/$(filename)/configure --prefix=$(gnuprefix)" 

    chdir=$(TrustedWorkDir)/$(filename)
    define=okay

 okay::

 "$(path)/make" 

     chdir=$(TrustedWorkDir)/$(filename)

####################################################

tidy:

  $(TrustedWorkDir) pattern=$(filename) r=inf rmdirs=true age=0


####################################################

#editfiles:
#
#@{ $(TrustedWorkDir)/$(filename)/configure-opts
#
#AppendIfNoSuchLine "Something ???"
#@}

####################################################

alerts:

 Force::

  ReturnVariables(none)
  ReturnClasses(success)

@end smallexample



A more complex example is given below:

@smallexample
  GetAnalysis("$@{parent1@}",param2,ReadFile("/etc/passwd",300))

    # The name of the method that is in modulesdir

    action=cf.methodtest                  

    # The variables that we get back should be called these names
    # with method name prefix

    returnvars=a,b,c,d               

    # This is an access list for returned classes. Classes will
    # only be handed back if they are included here

    returnclasses=define1,define2,class1 

    # The host(s) that should execute the method

    server=localhost                    

    # Only localhost can decide these - not a remote caller
    #    owner=25
    #    group=root
    #    chdir=/var/cfengine
    #    chroot=/tmp

@end smallexample
Here the function being called is the cfengine program @file{cf.methodtest}.
It is passed three arguments: the contents of variable @var{parent1}, the literal
string "param2" and the first 300 bytes of the file @file{/etc/passwd}.
On return, if the method gets executed, the values will be placed in the four
variables:

@smallexample
$(GetAnalysis.a) $(GetAnalysis.b) $(GetAnalysis.c) $(GetAnalysis.d)
@end smallexample
If the classes @code{define1} etc, are returned by the method, then we
set them also in the main program as
@smallexample
GetAnalysis_define::
@end smallexample
In other words, the class name is also prefixed with the method name to distinguish it.
(@code{returnclasses} works like an access
control list for setting classes, deciding whether or not the main
script should accept the results from the child method.). The remaining options are as those
for executing shell commands, and apply only on the host that executes
the function.

Both the client and server hosts must have a copy of the same method
declaration. The client should have a non-empty @code{server=} declaration.
The server side should have no @code{server=} declaration unless it is sending
the request on recursively to other hosts.
At present only requests to localhost are allowed, so only there is automatic
access to the rule.

The cfagent file that contains the method code must have the following
declarations:

@cartouche
  control:

    MethodName       = ( @var{identifier} )
    MethodParameters = ( @var{spaced list of recipient variables or files} )
 
   # ....

  alerts:

   # Return variables are alerts to parent

    ReturnVariables(@var{comma separated list of variables or functions or void})
    ReturnClasses(@var{comma separated list of classes})

@end cartouche
e.g.

@smallexample
control:

 MethodName       = ( GetAnalysis )
 MethodParameters = ( value1 value2 /tmp/file1 )
 
 # ....

alerts:

  # Return variables are alerts to parent

  ReturnVariables("$@{var1@}","$@{var2@}","var3",literal_value)
  ReturnClasses(class1,class2)

@end smallexample

The parameters transmitted by the parent are read into the formal
parameters @code{value1}, @code{value2} and the the file excerpt is
placed in the temporary file @file{/tmp/file1}.

The return classes are passed in their current state to the parent;
i.e. if class1 is defined then it is offered to the parent, but if it
is not defined in the method, it is not passed on. The parent can then
choose to accept or ignore the value.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node remotehost examples,  , localhost examples, methods
@subsection Remote host examples

Methods can also be scheduled for execution on remote hosts.
@itemize
@item Both hosts must have an identical copy of the method stanza
@item Public keys must be exchanged between the cooperating hosts
@item Access must be granted to @file{/var/cfengine/rpc_out} in cfservd.
@end itemize

Remote method execution is the same as local method execution except for
some additional requirements. A list of collaborating peers must be added
to the control section of @file{update.conf}.
In order the the requests to be collected automatically, you must have @code{copy}
in the action sequence of the @file{update.conf} file.


@smallexample
control:

 MethodPeers = ( @var{hostname list} ) # Must have copy in actionsequence

@end smallexample
This list tells the agent which remote hosts to collaborate with, i.e.
whom should we contact to look for work that we have promised to perform?
In order the the requests to be collected automatically, you must have @code{copy}
in the action sequence of the @file{update.conf} file.

For example, to make two hosts collaborate:

@smallexample
methods:

 host1|host2::

  MethodTest("my test!")

  action=cf.methodtest
  server=host2.iu.hio.no
  returnclasses=null
  returnvars=retval
  ifelapsed=120
@end smallexample

Note that an important aspect of remote method invocation is that there is only
voluntary cooperation between the parties. A reply bundle from a finished method
can collected from a server by the client many times, causing the classes
and variables associated with it to be defined at regular intervals, controlled
by the ifelapsed time. To avoid multiple actions, you should lock methods or
their follow-up actions with long ifelapsed times. This is a fundamental `feature'
of voluntary cooperation: each party must take responsibilty for the sense of what
it receives from the other. This feature will not be to everyone's taste, and it
is unconventional. However, voluntary cooperation provides a way of collaborating
without trust in a framework that forces us to confront the security issues directly.
As such, it is a successful experiment.



@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node miscmounts, mountables, methods, Cfagent reference
@section miscmounts
@cindex Mounting filesystems.
@cindex Miscellaneous mount operations
@vindex miscmounts

If you do not use the cfengine model for statically mounting NFS
filesystems (or if there are filesystems which do not naturally fall
into the bounds of that model) then you can still statically mount
miscellaneous filesystems using a statement of the form:

@cartouche

@w{}
@smallexample

miscmounts:

   @var{class}::

      @var{infohost}:@var{source-directory} @var{destination} @var{mode}

      @var{infohost}:@var{source-directory} @var{destination} mode=@var{mode}

     ifelapsed=@var{mins} expireafter=@var{mins}

@end smallexample 
@end cartouche

@noindent
For example

@smallexample

   physics::

    # old syntax

      libraryserver:/$(site)/libraryserver/data1 
                          /$(site)/libraryserver/data1 ro

    # consistent syntax

      libraryserver:/$(site)/libraryserver/data2
                          /$(site)/libraryserver/data2 mode=ro

      host:/foo /foo mode=rw,bg,hard,intr

@end smallexample

@noindent
This statement would mount the directory
@file{/$(site)/libraryserver/data} physically attached to host
libraryserver onto a directory of the same name on all hosts in the
group @code{physics}.  The modes @code{ro} and @code{rw} signify
read-only and read-write respectively.
If no mode is given, read-write is assumed.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node mountables, processes, miscmounts, Cfagent reference
@section mountables
@cindex Mountable resources, defining
@cindex Defining a mountable
@vindex mountables

The @code{mountables} declaration need only be used if you are using
cfengine's model for mounting NFS filesystems.  This declaration informs
hosts of what filesystem resources are available for mounting.  This
list is used in conjunction with @code{binservers} and
@code{homeservers} to determine which filesystems a given host should
mount, according to the cfengine model.

The syntax of the list is:

@smallexample
mountables:

   @var{class}::
       "filesystem to mount"
	   readonly=@b{false/off}/@var{true/on}
	   mountoptions=@var{nfs-options}

@end smallexample
e.g.

@smallexample

mountables:

   @var{class}::

   server:/site/server/u1
   server:/site/server/local
   linuxhost:/site/linuxhost/local
   linuxhost:/site/linuxhost/u1


@end smallexample 

@noindent
Notice that binary and home-directory filesystems are mixed freely here.
Cfengine determines which of the entries are homedirectories using the
@code{homepattern} variable.
@vindex homepattern
@cindex Homepattern variable.

Every time you add a disk or a mountable partition to your network, you
should add the partition to the list of mountables.

@emph{NOTE: This list is read in order, top down.  Cfengine looks for
the first filesystem matching a given binary server when expanding the
variable @code{$(binserver)}, so sometimes the ordering of filesystems
matters.}

This list can be accessed in editfiles, to allow straightforward
configuration of the automounter, using the command @code{AutomountDirectResources}.


@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node processes, packages, mountables, Cfagent reference
@section processes

Using the processes facility, you can test for the existence of
processes, signal (kill) processes and optionally restart them
again. Cfengine opens a pipe from the system ps command and searches
through the output from this command using regular expressions to match
the lines of output from @samp{ps}.  The regular expression does not
have to be an exact match, only a substring of the process line.  The
form of a process command is

@cartouche

@w{}
@smallexample
processes:

  @var{class}::

    @var{"quoted regular expression"} 

                        restart @var{"shell command"} 
                        useshell=@b{true}/@var{false/dumb}
                        owner=@var{restart-uid}
                        group=@var{restart-gid}
                        chroot=@var{directory}
                        chdir=@var{directory}
                        umask=@var{mask}

                        signal=@var{signal name}
                        matches=@var{number}
                        define=@var{classlist}
                        elsedefine=@var{classlist}

                        action=@b{signal}@var{/do/warn/bymatch}
                        include=@var{literal}
                        exclude=@var{literal}
                        filter=@var{filter_name}

                        syslog=@var{true/on}/@var{false/off}
                        inform=@var{true/on}/@var{false/off}
                        audit=@var{true/on}/@var{false/off}

                        ifelapsed=@var{mins} 
                        expireafter=@var{mins}

    SetOptionString @var{"quoted option string"}

@end smallexample
@end cartouche
@cindex umask

By default, the options sent to ps are "-aux" for BSD systems and "-ef"
for System V.  You can use the @code{SetOptionString} command to redefine
the option string. Cfengine assumes only that the first identifiable number
on each line is the process identifier for the processes, so you must not
choose options for ps which change this basic requirement (this is not a
problem in practice). Cfengine reads the output of the ps-command normally only
once, and searches through it in memory. The process table is only
re-consulted if @code{SetOptionString} is called. The options have the
following meanings:

@table @code

@item signal=@var{signal name}
This option defines the name of a signal which is to be sent to all processes
matching the quoted regular expression. If this option is omitted, no signal
is sent. The signal names have the usual
meanings. The full list, with largely standardized meanings, is

@smallexample
   hup       1   hang-up
   int       2   interrupt
   quit      3   quit
   ill       4   illegal instruction
   trap      5   trace trap
   iot       6   iot instruction
   emt       7   emt instruction
   fpe       8   floating point exception
   kill      9   kill signal
   bus      10   bus error
   segv     11   segmentation fault
   sys      12   bad argument to system call
   pipe     13   write to non existent pipe
   alrm     14   alarm clock
   term     15   software termination signal
   urg      16   urgent condition on I/O channel
   stop     17   stop signal (not from tty)
   tstp     18   stop from tty
   cont     19   continue
   chld     20   to parent on child exit/stop
   gttin    21   to readers pgrp upon background tty read
   gttou    22   like TTIN for output if (tp->t_local&LTOSTOP)
   io       23   input/output possible signal
   xcpu     24   exceeded CPU time limit
   xfsz     25   exceeded file size limit
   vtalrm   26   virtual time alarm
   prof     27   profiling time alarm
   winch    28   window changed
   lost     29   resource lost (eg, record-lock lost) 
   usr1     30   user defined signal 1
   usr2     31   user defined signal 2

@end smallexample
@noindent
Note that cfengine will not attempt to signal or restart processes 0 to 3
on any system since such an attempt could bring down the system. The only
exception is that the hangup (hup) signal may be sent to process 1
(init) which normally forces init to reread its terminal configuration
files.
@cindex Processes, 0 to 3

@item restart @var{"shell command"}

Note the syntax: there is no equals sign here.  If the keyword `restart'
appears, then the next quoted string is interpreted as a shell command
which is to be executed after any signals have been sent.  This command
is only issued if the number of processes matching the specified regular
expression is zero, or if the signal sent was signal 9 (sigkill) or 15
(sigterm) , i.e.  the normal termination signals.  This could be used to
restart a daemon for instance. Cfengine executes this command and
@emph{waits} for its completion so you should normally only use this
feature to execute non-blocking commands, such as daemons which
dissociate themselves from the I/O stream and place themselves in the
background. Some unices leave a hanging pipe on restart (they never
manage to detect the end of file condition). This occurs on POSIX.1 and
SVR4 popen calls which use wait4. For some reason they fail to find and
end-of-file for an exiting child process and go into a deadlock trying
to read from an already dead process. This leaves a zombie behind (the
parent daemon process which forked and was supposed to exit) though the
child continues.  A way around this is to use a wrapper script which
prints the line "cfengine-die" to STDOUT after restarting the
process. This causes cfengine to close the pipe forcibly and continue.
@cindex Deadlock zombie bug in restart
@cindex Restart zombie deadlock bug
Cfengine places a timeout on the restart process and attempts to
clean up zombies, but you should be aware of this possibility.
@cindex Setting uid on restarted processes

@item owner=,group=
Sets the process uid and gid (setuid,gid) for processes which are
restarted. This applies only to cfengine run by root.

@item chroot
Changes the process root directory of the restarted process, creating
a `sandbox' which the process cannot escape from. Best used together with
a change of owner, since a root process can break out of such a confinement
in principle.

@item chdir
Change the current working directory of the restarted process.

@item useshell=@var{true/false/dumb}
When restarting processes, cfengine normally uses a shell to
interpret and execute the restart command. This has inherent
security problems associated with it. If you set this option to
false, cfengine executes restart commands without using a shell.
This is recommended, but it does mean that you cannot use any
shell operators or features in the restart command-line.

Some programs (like cron) do not handle I/O properly when they fork
their daemon parts, this causes a zombie process and normally
hangs cfengine. By choosing the value `dumb' for this, cfengine
ignores all output from a program and does not use a startup shell.
This prevents programs like cron from hanging cfengine.

@item matches=@var{number}
This option may be used to set a maximum, minimum or exact number of
matches. If cfengine doesn't find a number of matches to the regular
expression which is in accordance with this value it signals a warning.
The @samp{<}, @samp{>} symbols are used  to specify upper and lower
limits. For example,

@smallexample
  matches=>6  # warn number of matches is greater than or equal to 6
  matches=1   # warn if not exactly 1 matching process
  matches=<2  # warn if there are less than or equal to 2 matching processes
@end smallexample
@cindex Processes, counting


@item include=@var{literal}
Items listed as includes provide an extra level of selection after the
regular expression matches have been expanded. If you include one
include option, then only lines containing one or more of the literal
strings or wildcards will be matched. 

@item exclude=@var{literal}
Process lines containing literal strings or wildcards in exclude
statements are not matched. Excludes are processed after regular
expression matching and after includes.


@item define=@var{classlist}
The colon, comma or dot separated list of classes becomes activated if the
number of regular expression matches is non-zero.

@item elsedefine=@var{classlist}
The colon, comma or dot separated list of classes becomes activated if the
number of regular expression matches is zero.


@vindex bymatch
@vindex signal
@item action=@var{signal/do/warn/bymatch}
The default value of this option is to silently send a signal
(if one was defined using the @code{signal} option) to matching
processes. This is equivalent to setting the value of this
parameter to @samp{signal} or @samp{do}. If you set this option
to @samp{warn}, cfengine sends no signal, but prints a message
detailing the processes which match the regular expression.
If the option is set to @code{bymatch}, then signals are only sent
to the processes if the matches criteria fail.
@cindex Processes, checking existence of
@cindex Processes, signalling

@end table

Here is an example script which sends the hang-up signal to cron,
forcing it to reread its crontab files:

@smallexample

processes:

   "cron" signal=hup

@end smallexample

@noindent
Here is a second example which may be used to restart the nameservice
on a Solaris system:

@smallexample

processes:

   solaris::

       "named" signal=kill restart "/usr/sbin/in.named"

@end smallexample

@noindent
A more complex match could be used to look for processes belonging to
a particular user. Here is a script which kills ftp related processes
belonging to a particular user who is known to spend the whole day
FTP-ing files:

@smallexample

control:

    actionsequence = ( processes )

  #
  # Set a kill signal here for convenience
  #

    sig = ( kill )

  #
  # Better not find that dumpster here!
  #

    matches = ( 1 )

processes:

   #
   #  Look for Johnny Mnemonic trying to dump his head, user = jmnemon
   #

   ".*jmnemon.*ftp.*" signal=$(sig) matches=<$(matches) action=$(do)

   # No mercy!

@end smallexample

@noindent
The regular expression @samp{.*} matches any number of characters, so this
command searches for a line containing both the username and something to
do with ftp and sends these processes the kill signal.

You can arrange for signals to be sent, only if the number of matches
fails the test. The @code{action=bymatch} option is used for this.
For instance, to kill process `XXX' only if the number
of matches is greater than 20, one would write:

@smallexample

processes:

"XXX" matches=<20  action=bymatch signal=kill

@end smallexample

See also filters @xref{filters}, for more complex searches.
@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node packages, rename, processes, Cfagent reference
@section Packages
@cindex packages
@cindex Checking for installed packages

The packages action allows you to check for the existance of packages
on the system, as determined by the package database you select.  Optionally,
if a package install command was specified, the package can be installed
if it is not there.

This operation is set up such that it tries not to make assumptions about
the package manager in use.  For example, it should be possible to use
RPM on a Solaris box.

The syntax summary is:

@cartouche

@w{}
@smallexample

packages:

   @var{class}::

      @var{package-name}
                        pkgmgr=@b{none}/@var{rpm/dpkg/sun/aix/portage/freebsd}
                        cmp=@b{eq}/@var{lt/gt/ge/le/ne}
                        version=@var{version-string}
                        define=@var{class-list}(,:.)
                        elsedefine=@var{class-list}(,:.)
                        action=@b{none}/@var{install/remove/upgrade/fix}

                        ifelapsed=@var{mins} 
                        expireafter=@var{mins}

                        audit=@var{true/on}/@var{false/off}
                        inform=@var{true/on}/@var{false/off}

EXAMPLES:
packages:
  # install newpackage 1.10 if newpackage 1.0 or greater isn't installed
  newpackage-1.10 action=install
                cmp=ge
                version=1.0

  # upgrade any installed versions of compromised to at least 1.2
  compromised-1.2 action=upgrade
                version=1.2
                cmp=le

  # Make sure that version 1.2 is installed
  compromised-1.2 action=fix
                version=1.2
                cmp=le

  # remove any version of useless
  useless action=remove
                version=0.1
                cmp=ge

@end smallexample
@end cartouche
@table @code

@item action
@vindex action=
Determines the action taken if the comparison matches.

@itemize @bullet
@item
@code{install}
Install this package if the version comparison does not match.

@item
@code{upgrade}
Upgrade this package if the version comparison does match.

@item
@code{fix}
Install or Upgrade this package if the version comparison does match.

@item
@code{remove}
Uninstall this package if the version comparison does match.
@end itemize

@item cmp
@vindex cmp=
Determines how the version of the installed package will be compared to
that specified by the @code{version} attribute.  Possible values include:

@itemize @bullet
@item
@code{eq}
The version installed must be equal to @code{version}
@item
@code{lt}
The version installed must be less than @code{version}
@item
@code{gt}
The version installed must be greater than @code{version}
@item
@code{le}
The version installed must be less than or equal to @code{version}
@item
@code{ge}
The version installed must be creater than or equal to @code{version}
@item
@code{ne}
The version installed must not be equal to @code{version}
@end itemize

The default value for this attribute is @code{eq}.

Note that @code{cmp} is used differently for install versus upgrade, fix and remove. 
The action is performed when false for install, but when true for upgrade, fix or remove.

@item version
@vindex version=
Specifies the package manager specific version string to match.  If
this is not specified, then any version matches, and the value of
the @code{cmp} attribute is ignored.  See the allowed values of
@code{pkgmgr} below for an explation of how each package manager
will interpret this.

@item pkgmgr
@vindex pkgmgr=
Selects the package manager database to query.  This defaults to either
the value of the @code{DefaultPkgMgr} variable, or if that is not set,
there is no default.  In that case, no checking will be done unless
@code{pkgmgr} is set explicitly for each package.  Note that the default
value '@samp{none}' listed is merely a pseudo-value, and cannot actually
be used, since it would make no sense anyway.

Each package manager will interpret the @code{version} and @code{cmp}
attributes in its own way.  For example, when you use
@code{pkgmgr=rpm}, the comparison will be done with the same rules that
RPM use if it were not being run through cfengine.  Freebsd actually
invokes the standard system utility to do the comparisons for it, etc.

Currently, the following package managers are supported:

@table @code
@item rpm
@cindex RPM Database Queries
This uses the rpm command, which cfengine expects to find as @file{/bin/rpm}
to query the machine's RPM database.  The @code{rpm} check assumes that you
are using a version of RPM that understands the concept of an epoch,
which means that you will want to use RPM version 3.0.3 or greater.
Versions as early as 2.5.6 may work, but it is doubtful.  If multiple
packages of the same name are installed (i.e. kernel), then the check
considers the package to be installed at the specified version if
@b{at least one} of them satisifies the criteria specified by @code{cmp} and
@code{version}.

The format of a RPM version string is: [epoch:]version[-release].  The
version[-release] can be seen by simply running: @command{rpm -q <pkg>}.
In order to see the epoch, you must use a query format, like this:
@command{rpm -q --queryformat "%@{EPOCH@}:%@{VERSION@}-%@{RELEASE@}\n" <pkg>}.
Most packages do not have an epoch, and will print @samp{(none)} in the
epoch space.  In recent incarnations of RPM, the absense of an epoch
is interpreted as 0.  This is also how cfengine will interpret it.
@emph{Be careful with this.  If the installed version
of a package has an epoch greater than 0, and you do not specify the epoch,
unexpected results may happen.}  For example, if you have a package installed,
@samp{foo-1:2.0-1}, and you specify a @code{version=3.0-1} and a
@code{cmp=gt}, the check will be true, because the installed version has
an epoch of 1, and you did not specify an epoch, which implies you wanted
an epoch of 0.  The rule here is basically to always check the epoch of
the package you really want, and specify it.  It may take a few extra
extra seconds to check, but it will save you lots of headaches later.

@item portage
@cindex Gentoo Package Database Queries

This uses the emerge command to install packages on a Gentoo Linux
system.  The `portage' Python module is used to query the system and
find installed packages.  The @i{package_name} and @i{version} support
any package that conforms to the Gentoo package naming specification
@url{http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml?part=2&chap=1#doc_chap2_sect2},
and even most of those in the Portage tree that do not.  Because
Gentoo package atoms are flexible, you can use the name of the
package, along with a @i{version} and the @i{cmp} cfengine logic, or
you can put the comparison operator and version in the @i{package_name}
field and leave out the @i{cmp} operator.  Because cfengine builds the
install string out of the package name, and ignores the @i{version}
you were comparing against, using a package atom with a version is the
only way to have a specific version emerged.

@smallexample

 packages:

  any::

   # if the version of tar is less than 1.16-r2,
   # then the *latest* version of tar will be installed:

   app-arch/tar cmp=ge version=1.16-r2 action=install

   # This is equivalent, but uses the package atom to
   # define the version comparison:

   >=app-arch/tar-1.16-r2 action=install

@end smallexample

@item dpkg
@cindex Debian Package Database Queries
Please document me!

@item sun
@cindex Sun Package Database Queries
Please document me!

@item freebsd
@cindex FreeBSD Package Database Queries

FreeBSD has fully working install/upgrade/delete management for
packages.  You can either get the latest version from a package repository,
or define the explicit version to install.

@smallexample

# install new package from FreeBSD ports tree
control:
  DefaultPkgMgr = ( freebsd )
  FreeBSDInstallCommand = ( "/usr/sbin/pkg_add -r %s" )

packages:
  bsdsar action=install

# install a specific version from a local repository
control:
  DefaultPkgMgr = ( freebsd )
  FreeBSDInstallCommand = ( "/usr/sbin/pkg_add http://server/path/%s" )

packages:
  bsdsar-1.10_2 action=install
@end smallexample

Note that specifying the version of the package that is part of the freebsd package filename is required if not using "-r" mode.
It does not use this version for comparison, just for the package filename to install.

You can also backgrade if you know that 1.2 is bad for instance.

@smallexample
packages:
  bsdsar-1.10_2 action=upgrade
                version=1.10_2
                cmp=gt
@end smallexample

The only gotcha about FreeBSD installation is trying to specify the package
source location.  Due to the unfortunate fact that freebsd doesn't provide a
command line option -- only an environment variable -- for specifying
the source repository, you have a few options.

Get it from the main FreeBSD binary package home:

@smallexample
  FreeBSDInstallCommand = ( "/usr/sbin/pkg_add -r %s" )
@end smallexample

Get it from a mounted directory or http server

@smallexample
  FreeBSDInstallCommand = ( "/usr/sbin/pkg_add /nfs/packages/%s" )
  FreeBSDInstallCommand = ( "/usr/sbin/pkg_add http://server/path/%s" )

@end smallexample

Or write a script that tells pkg_add where to find it, like so:

@smallexample
  FreeBSDInstallCommand = ( "/var/cfengine/packages/pkginstall %s" )
@end smallexample
such as 

@smallexample
#!/bin/sh
PACKAGESITE=http://my.local.repository/packages/
export PACKAGESITE
/usr/sbin/pkg_add -r $*
@end smallexample
@end table

@item define
Specifies the list of classes to define if the specified package/version was
installed (prior to actions taken if any)

@item elsedefine
Specifies the list of classes to define if the specified package/version was not
installed (prior to actions taken if any)

@item action
Specifies whether the packages should actually do anything about the
situation it finds.  The default for this is to do nothing.

For @code{install}, the action will be taken if the comparison returns false.

For @code{upgrade} and @code{remove}, the action will be taken if the comparison returns false.

The classes in @code{define} and @code{elsedefine} will always be defined,
as applicable, regardless of the action specified.

@table @code
@item install
Installs the package using the command associated with the selected
package manager, if it is not currently on the system at the requested
version, as follows:

@itemize @bullet
@item
RPM - 
RPMInstallCommand
@item
DPKG - 
DPKGInstallCommand
@item
SUN - 
SUNInstallCommand
@item
Gentoo - 
PortageInstallCommand
@item
FreeBSD - 
FreeBSDInstallCommand
@end itemize

Each variable is of the format:

@smallexample
FOOInstallCommand = ( "/usr/bin/foo --args %s --more-args" )
@end smallexample

The ---args are of course optional.  For FreeBSD and Sun, the %s is replaced with the package name
that was checked, and found to not be installed.  For all other package managers the %s can have
a space separated list of package names.

@item upgrade
Upgrades the package using the commands associated with the selected
package manager, first removal of the old package then installation of the new package.
Note that on some package managers this action is unnecessary because the package manager
will "do the right thing" when told to install a newer version.

@itemize @bullet
@item
FreeBSD - 
FreeBSDRemoveCommand followed by FreeBSDInstallCommand
Portage - 
Upgrade is generally not necessary since emerge will do the upgrade for you.
@end itemize

@item remove
Removes the package(s) using the command associated with the selected
package manager, if a matching package is found on the system, as follows:

@smallexample
FOORemoveCommand = ( "/usr/bin/foo --args %s --more-args" )
@end smallexample

The ---args are of course optional.  The %s is replaced with a space-separated
list of the package names that were checked, and found to be installed.
@end table
@end table

@noindent
NOTE: classes are defined according to the result of the check, not
any action performed as a result of that check.  In otherwords, if for
example you have a situation where a package is not installed,
and the action= is set to install, the classes in @code{elsedefine} will
be defined @b{regardless} of whether or not the install was successful.
Assuming the package installed, the next run of cfagent will pick up that
fact.  This has to be done since the package installs are batched, so there
is no reliable way to know if a given package was installed successfully.

@noindent
Examples:

@smallexample
packages:

    redhat_8_0::
        m4  version=0:1.4.1-11 cmp=eq pkgmgr=rpm elsedefine=needsm4
@end smallexample

@noindent
In this first example, we are looking for the m4 package at exactly version
0:1.4.1-11.  The installed m4 package on a redhat_8_0 box has no epoch
which is the same as zero.  Specifying it will keep you out of trouble.  This
check will cause @code{needsm4} to be defined if the exact version of
m4 specified is not installed.

@smallexample
control:
    redhat:;
        DefaultPkgMgr = ( rpm )

    gentoo::
        DefaultPkgMgr = ( portage )

packages:
    redhat_8_0::
        make version=0:4.5-2 cmp=ge define=hasmake elsedefine=needsmake

@end smallexample

@noindent
In the second example, we use the DefaultPkgMgr variable to set the default
for the @code{pkgmgr} attribute to @code{rpm}.  The actual version of make
installed on recent redhat_8_0 machine is 1:3.79.1-14.  Since the check is
for greater than or equal to this version, the hasmake class will be
defined.

@smallexample
control:
    redhat:;
        DefaultPkgMgr = ( rpm )
        RPMInstallCommand = ( "/usr/sbin/up2date %s" )

packages:
    redhat_8_0::
        make define=hasmake elsedefine=needsmake action=install
@end smallexample

@noindent
This example is much like the second example, except that if the package is
not installed, cfengine will attempt to install it using the command in
RPMInstallCommand, replacing the %s with the package name, @code{make}.
If there were multiple packages specified in this way, the package installation
would occur at the end of the package checks, and one command would be run,
with %s replaced with a list of all package names.  In this example we chose
not to use a version spec, but it is allowed, and as always, is optional.

@noindent
NOTE here that if make was not installed when the check is made,
@code{needsmake} is defined, regardless of whether or not the
install succeeds.  If the install is successful, the next cfagent
run will define @code{hasmake}.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node rename, required, packages, Cfagent reference
@section rename

As of version 2.1.0 rename is a synonym for disable, @xref{disable}.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node required, resolve, rename, Cfagent reference
@section required

This is a synonym for disks, @xref{disks}.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node resolve, scli, required, Cfagent reference
@section resolve

@cindex DNS
@cindex Resolver configuration
@cindex resolv.conf
@vindex resolve

The file @code{/etc/resolv.conf} specifies the default nameserver for
each host, as well as the local domain name.  This file can also contain
other information, but these are the only two things cfengine currently
cares about.  In specifying nameservers you should use the dotted
numerical form of the IP addresses since your system may not understand
the text form if it is not correctly configured.  You may list as many
nameservers as you wish, with the default server at the top of the list.
The resolver normally ignores entries if you add more than three.  The
statement:

@smallexample

resolve:

  mygroup::

     129.240.22.35
     129.240.22.222
     129.240.2.3

@end smallexample 

@noindent
declares a list of nameservers for hosts in the group or class
@code{mygroup}.  When you add the @code{resolve} command to the
@code{actionsequence}, this declaration together with the @code{domain}
variable (set here to @code{uio.no}) results in a
@code{/etc/resolv.conf} file of the form:

@w{}
@smallexample

domain uio.no
nameserver 129.240.22.35
nameserver 129.240.22.222
nameserver 129.240.2.3

@end smallexample 

@noindent
Note that the @code{resolve} action does not delete anything from the
file @code{/etc/resolv.conf} unless the @code{EmptyResolvConf} variable is set
to 'true' .  It adds nameservers which do not previously exist and
reorders the lines of servers which do exist.

As of version 1.3.11, you may use a quoted string to add non-nameserver
lines to this file. For example:

@smallexample

resolve:

  mygroup::

     129.240.22.35
     129.240.22.222
     "# Comment line"
     "order bind, files"

@end smallexample
@noindent
If the line begins with a non-numeric character, the word `nameserver'
is not added to the line.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node scli, shellcommands, resolve, Cfagent reference
@section scli

SCLI is an SNMP command line interpreter written by J@"urgen
Sch@"onwaelder of the Jacobs University of Bremen. It is a command
interpreter used to simplify the interaction with SNMP enabled
devices. SNMP is a stateless, UDP based network protocol for
communicating with supporting hardware. The SNMP model does not fit
very comfortably with the cfengine ``responsibility for self''
paradigm, but at some level SCLI can be viewed as just another form of
interpreted script. SCLI adds a level of user friendliness and
stateful behaviour to SNMP through its shell-like interface. This
turns out to be both a help and a hindrance to cfagent.

The intermingling of stateful and stateless processes in the dialogue
between cfengine and scli makes their integration non-trivial. Several
compromises have to be made to aid usability and these could lead to
difficulties in the practical use of the tools later.

The scli section of a cfagent configuration is a single script. The lines
are passed as a collective object to the scli interpreter, not line-by-line
as in other cases.

The basic approach is to open a pipe for the reading and writing of
dialogue with the interpreter. There are some limitations to Unix
pipes however, in particular input and output are separated which
makes per-transaction error control essentially impossible. A
work-around for this has been used in the test phase.

The cfengine interface is a special case of the @code{shellcommands}
interface, passing commands to SCLI instead of to @file{/bin/sh}.
The command options are the same as those below for @code{shellcommands}.


@cartouche

@w{}
@smallexample
shellcommands:

  @var{class}::

    "@var{scli-string}"  @var{shellcommand options}
    "@var{scli-string}"  

@end smallexample
@end cartouche

@vindex scli command interpreter
@vindex SNMP

@i{This integration was funded by the IST-EMANICS Network of Excellence in Network and
Service Management, of which Oslo University College and the Jacobs University of
Bremen are members}.


@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node shellcommands, strategies, scli, Cfagent reference
@section shellcommands

Cfengine focuses on fairly simple-minded tasks in order to be as general
as possible.  In many cases, you will therefore want to write a script to
do something special on your system.  You can still take advantage of
the classes you have defined by executing these scripts or shell
commands from this section.

The syntax is simply to quote the command you wish to be executed.

@cartouche

@w{}
@smallexample
shellcommands:

  @var{class}::

    "@var{command-string}"  

          timeout=@var{seconds} 
          useshell=@b{true}@var{/false}
          umask=@var{octal number}
          owner=@var{uid}
          group=@var{gid}

          background=@b{false}@var{/true}
          chdir=@var{directory}
          chroot=@var{directory}
          preview=@var{true}/@b{false}
          inform=@b{false}@var{/true}
          audit=@var{true/on}/@var{false/off}

          noabspath=@b{false}@var{/true}

          ifelapsed=@var{mins} 
          expireafter=@var{mins}

          define=@var{class-list}
          elsedefine=@var{class-list}

@end smallexample
@end cartouche
@cindex umask

@noindent
@table @code

@item @var{command-string}
This is the command to be executed.

@item @var{timeout} 
If you set the optional @var{timeout} parameter, then cfengine
will abort the specified shellcommand if it exceeds
the given time-limit (specified in seconds).
This can be useful for avoiding hung programs caused by hung
network connections, etc. Timeouts are generated by alarm interrupts
within a single agent. This can be contrasted with @code{expireafter}
in which a second agent is required to interrupt a command.
@cindex @code{timeout=} in shellcommands
@mbindex How can I set a timeout for a shell command?
@mbindex How can I avoid hanging shellcommands?
@mbindex Hanging commands, timeouts

@item @var{useshell}
Some program lines, especially those that do not use any shell-specific
capabilities (such as redirection and wildcard expansion) can be run without the shell.
This is typically more secure, as the command line is not altered by the
user or by the system.  It is also faster, as the shell does not have
to be spawned in order to run the given command.  Use the @var{useshell}
parameter to tell cfengine to not use the shell to run this shellcommand.

@item @var{umask}
The umask affects the permissions given to a file created by this shellcommand.
The umask specifies, specifically, the permissions that are to be taken away.

@item @var{owner}
@item @var{group}
The user and group ID's of the process can be set (using the @var{owner}
and @var{group} parameters respectively) to restrict the
permissions of the shellcommand. This can only be done if cfengine is
executed by root; otherwise, the user and group will remain that of the
the user who started cfengine.

@item @var{background}
Run this command in the background if this is specified true.  This will make
cfengine run faster, but no tests can be made (at least directly) on the results
of this command. Also when jobs are backgrounded, the output in verbose mode 
can be somewhat erratic due to the unsychnronized streams.

@item @var{chdir}
Change to the specified directory before running this command.

@item @var{chroot}
The @code{chroot} option changes the process root directory of the
command, creating a `sandbox' which the process cannot escape from. Best
used together with a change of owner (using the @code{owner} parameter),
since a root process can break out of a chrooted environment.

@item @var{preview}
The @code{preview} option means that the shellcommand will also be executed during
the @w{@code{--dry-run}} (@code{-n}) options. This allows cfengine to be more aware
of the results of scripts which define classes. This option should be used
with care.

Scripts should conform to the protocol of not executing unnecessary commands
when the classes @code{opt_dry_run} is defined.
@cindex Previewing shellcommands
@cindex @code{--dry-run} option

@item @var{inform}

@item @var{noabspath}
Normally, cfagent requires the command string to begin with a @samp{/}
since it is dangerous to rely on an implicit path. However, sometimes it
it is appropriate to override this.  This behavior can be overridden using
the @var{noabspath} parameter.
@cindex noabspath
@vindex noabspath 
@mbindex Shellcommands must start with absolute path
@mbindex Absolute path and shellcommands

@item @var{ifelapsed}
The shellcommand specified will not be run unless the specified amount of
time (in minutes) has elapsed since the command was previously run.

@item @var{expireafter}
If this amount of time (in minutes) has elapsed since the command started,
then the command is aborted by a second agent that is patrolling the system.

@item @var{define}
Define the specified classes if the command finishes successfully.

@item @var{elsedefine}
Define the specified classes if the command does not finish successfully.

@end table

Variable substitution works within the strings.  Here are some examples.

@smallexample

shellcommands:

   sun4::

       "/usr/lib/find/updatedb"

   AllHomeServers.Sunday::

       "/dir/noseyparker /$(site)/$(host)/u1 $(sysadm) nomail"

   AllBinaryServers.sun4.Saturday::

      "/usr/etc/catman -w -M /usr/local/man"
      "/usr/etc/catman -w -M /usr/local/X11R5/man"
      "/usr/etc/catman -w -M /usr/man"
      "/usr/etc/catman -w -M /usr/local/gnu/man"

@end smallexample 

@noindent

If you need to write more advanced scripts which make detailed use of the
classes defined by cfengine, use the @code{$(allclasses)} variable to send
a complete list of classes to your script.  An enviornment variable,
CFALLCLASSES, is set and is in the format

@smallexample

CFALLCLASSES=class1:class2:class3...

@end smallexample

@noindent
This variable is kept up-to-date at any given time with only the classes
which are defined.  The command line option @samp{-u} or
@samp{--use-env} can be used to define an environment variable which
will be inherited by all scripts and contains the same information.
This is not the standard approach, since some systems cannot
cope with this rapid change of environment and generate a Bus Error.
@cindex CFALLCLASSES
@cindex allclasses variable
@cindex Scripts and class information
@cindex Class information, passing to scripts

Commands can be iterated over variable lists, provided there is
at least one space between each variable. For example:

@smallexample

control: 

      actionsequence = 
         (
         shellcommands
         )

 var1 = ( a:b:c )
 var2 = ( x:y:z )

shellcommands:

   "/bin/echo $(var1) $(var2)"

@end smallexample
@noindent
This iterates over all values of the list variables. @xref{Iteration over lists}.
@cindex Iterating over lists in shellcommands
If you are iterating over a list, the time limit (in seconds) which is
specified in the @var{timeout} parameter applies to each separate
iteration, not to the sum total of all the iterations.
@cindex Timeouts during iterations

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node strategies, tidy, shellcommands, Cfagent reference
@section strategies
@cindex Gaming stratgies
@cindex Strategy, random
@vindex Randomizing strategy

Strategies (introduced in cfengine version 2.0)
are a way of picking from a set of classes randomly.
Each class is a possible course of action.
A strategy group (of classes) is defined as follows:

@smallexample
strategies:

  @{ my_strategy_alias

  class1: "2"
  class2: "3"
  class3: "$(value)"
  class4: "6"
  class5: "1"
  @}

tidy:

 class1.Hr00::  

   /home pat=*.mp3 age=0

 class2.Hr02::  

   /home pat=*.wav age=0
@end smallexample

The idea here is to randomly pick from a selected set of
classes.

Specifically, each strategy is a class which is defined with a certain
probability. An integer weight is provided in quotes to represent the
probability weight of the associated class. When cfengine is run,
it randomly picks one of the classes from each strategy.
Using strategies, you can choose different ways of
configuring or protecting a system, at random, thus confounding
environmental attempts to break into the system.

Note that each strategy has a formal name (such as @samp{my_strategy_alias}
in the example), but this name is not used to
attach a strategy to an action the same way that filters or ACLs are.

@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node tidy, unmount, strategies, Cfagent reference
@section tidy
@cindex Tidying files
@cindex Deleting files
@vindex tidy

The tidy function is used to delete (remove permanently) unwanted files
from a system.  It is useful for tidying up in @code{/tmp} or cleaning
out @code{core} files from users' home directories.  The form of an
entry is:

@cartouche

@w{}
@smallexample
tidy:

  @var{class}::

      @var{/directory} 
                       pattern/include=@var{wildcard} 

                       recurse=@var{number/inf} 
                       age=@var{days} 
                       size=@var{number/empty}
                       type=@var{ctime/mtime/}@b{atime}
                       dirlinks=@var{keep/tidy/delete}
                       rmdirs=@var{[true/all]/[@b{false/none}]/sub}
                       links=@b{stop/keep}@var{/traverse/tidy}
                       compress=@var{true/on}/@b{false/off}

                       define=@var{classlist}
                       elsedefine=@var{classlist}

                       syslog=@var{true/on}/@var{false/off}
                       inform=@var{true/on}/@var{false/off}
                       audit=@var{true/on}/@var{false/off}

                       ifelapsed=@var{mins} 
                       expireafter=@var{mins}

                       filter=@var{filter alias}
                       ignore=@var{pattern}
                       exclude=@var{pattern}
                       xdev=@var{true/on}/@b{false/off}

@end smallexample 
@end cartouche

@noindent
Note that, each of the options below
can be written in either upper or lower case and abbreviated by any
unique abbreviation.
@vindex p=
@vindex pattern
@vindex a=
@vindex age
@vindex r=
@vindex recurse
@cindex compress
@cindex Compression during tidy

@table @code

@item @var{/directory}
This is the directory name to directories which mark the start of a
search for files matching certain wildcards.  The wildcard @code{home}
may be used instead of an explicit directory, in which case cfengine
iterates over all home directories.  It is compulsory to specify a
directory.

@item pattern=@var{wildcard} or include=@var{wildcard}
A wildcard or filename to match the files you wish to be deleted.  The
pattern may contain the special symbols @samp{?} which matches a single
character and @samp{*} which matches any number of characters as in the
shell. These two options are synonymous, as of version 2.0.x.
Note that, this pattern is processed as a filter before any other filter
and, for safety reasons, it defaults to nothing. Thus, if you want to
use a filter to select the files, you should set @samp{pattern=*}, else
the filter will not see any files at all.
@cindex pattern= and filtering
@vindex Wildcards

@item exclude=@var{wildcard}
This does not work for the home directive; use the global ignore list for this.

@item ignore=@var{wildcard}
This does not work for the home directive; use the global ignore list for this.

@item recurse=@var{number/inf}
This specifier tells cfengine whether or not to recurse into
subdirectories.  If the value is zero, only the named file or directory
is affected.  If the value is 1, it will open at most one level of
subdirectory and affect the files within this scope.  If the value is
@code{inf} then cfengine opens all subdirectories and files beginning
from the specified filename. @xref{Recursion}.

@item age=@var{days}
The age of a file in days represents a minimum @emph{access} time
elapsed before the file will be deleted.  In other word a file will be
deleted if it has not been accessed for @var{days} days.

@item links=@var{stop/traverse/tidy}
Normally cfengine does not descend into subdirectories which are pointed
to by symbolic links.  If you wish to force it to do so (without using
the @code{-l} command line option) you may give this option the value
@code{true}, or @code{traverse}, or @code{follow}.  To specify no
recursion you set the value @code{false} or @code{stop}.
@cindex Links, traversing in searches
@vindex -l
@cindex -l option
Note that the value set here in the cfengine program @emph{always
overrides} the value set by the @code{-l} command line option, so you
can protect certain actions from this command line option by specifying
a negative value here.  If you specify no value here, the behaviour is
determined by what you specify on the command line.

The value @code{links=tidy} has the same effect as the @samp{-L} command
line option except that here it may be specified per item rather than
globally.  Setting this value causes links which point to non-existent
files to be deleted. This feature will not work on commands with the
@samp{home} wildcard feature.  If you want to clean up old links you
should either user a @code{files} command or the command line option
which sets the tidy feature globally.
@cindex Deleting stale links
@cindex Links, deleting stale

@item size=>@var{number/empty}
Old syntax @code{size=@var{number/empty}}.
The value of this parameter decides the size of files to be deleted.
Files larger than this value will be deleted if they also are older than
the time specified in @code{age}. The default size is zero so that any
file which gets matched by another critereon is deleted. However, if you
want to single out only totally empty files, the @code{empty} may be used.
With this option only empty files, nevery files with anything in them,
 will be deleted, if older than @code{age}. By default, the filesizes
are in kilobytes, but kilobytes and megabytes may also be specified by
appending b,k,m to the numbers. Only the first character after the
number is significant so you may write the numbers however it might be
convenient, e.g. @kbd{14k}, @kbd{14kB}, @kbd{14kilobytes}, the same as
for @code{disable}.
@cindex Specifying file sizes
@cindex File sizes, specifying
@cindex Megabytes, filesize unit
@cindex Kilobyte, filesize unit
@cindex Empty files
@cindex Tidying empty files

@item type=@var{ctime/mtime/atime}
This value is used to set the type of time comparison made using
@code{age}. The default is to compare access times (atime) or
the last time the file was read. A comparison by modification 
time (mtime) uses the last time the contents of the file was
changed. The ctime parameter is the last time the contents, owner
or permissions of the file were changed. Note that on directories,
mtime is always used for comparisons, since the very act of stat'ing
alters atime and makes this comparison meaningless.

@item dirlinks=@var{keep/tidy/delete}
This value is used to decide whether cfengine will delete
links which point to directories. The default value is to keep
the links. Note that, if the @code{travlinks} option is switched on,
cfengine will not tidy or delete links which point to directories,
instead it follows them into the subdirectory. This is a supplement
to the @code{rmdirs} option. You need both to make links
to directories disappear. Note that, even if @code{travlinks}
is set to true, cfagent will not follow symbolic links that are
not owned by the agent user ID; this is to prevent link race attacks,
in which users with write access could divert the agent to another part
of the filesystem,
@cindex Security, link races and travlinks
@cindex travlinks

@cindex Tidy by ctime, mtime, atime
@cindex ctime tidies
@cindex mtime tidies
@cindex atime tidies

@item rmdirs=@var{true/false/all/sub}
Normally cfengine will not delete directories. If this option is
set to `true' then cfengine will delete any directories which
are @emph{empty}. Non-empty directories will not be touched and no
message will be given unless in verbose mode. Note that this
option overrides the above option @code{dirlinks}, so that even
links which point to empty directories will be removed.
If this is set to `sub' then the topmost directory will not
be removed, only sub-directories.

@cindex rmdirs
@cindex Removing directories
@cindex Deleting directories
@cindex Directories, deleting

@item define=@var{classlist}
The colon, comma or dot separated list of classes becomes defined
if any file matching the specified pattern is deleted.

@item xdev
Prevents cfengine from descending into file systems that are not on the
same device as the root of the rescurion path.
@cindex xdev


@end table
Take a look at the following example:

@smallexample
tidy:

   AllHomeServers::

       home     pattern=core   R=inf age=0
       home     pattern=*~     R=inf age=7
       home     pattern=#*     R=inf age=30


   any::

       /tmp/    pat=*            R=inf   age=1
       /        pat=core         R=2     age=0
       /etc     pat=hosts.equiv  r=0     age=0

@end smallexample 

In the first example, all hosts in the group @code{AllHomeServers}
iterate a search over all user home directories looking for `core' files
(older than zero days) and @code{emacs} backup files @samp{*~},
@samp{#*} older than seven days.

The default values for these options are the empty string for the
wildcard pattern, zero for the recursion and a specification of the age
is compulsory.

@cindex .cfengine.rm
@vindex .cfengine.rm
When cfengine tidies users' home directories, it keeps a log of all the
files it deletes each time it is run.  This means that, in case of
accidents, the user can see that the file has been deleted and restore
it from backup.  The log file is called @code{.cfengine.rm} and it is
placed in the home directory of each user.  The file is owned by root,
but is readable to the user concerned.


@page

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node unmount,  , tidy, Cfagent reference
@section unmount

@cindex Unmounting filesystems
@vindex unmount

The unmount function unmounts non-required filesystems and removes the
appropriate entry from the filesystem table (@code{/etc/fstab} or
equivalent).  The syntax is simply

@cartouche

@w{}
@smallexample
unmount:

   @var{class}::
 
      @var{mounthost}:@var{filesystem}

        deletedir=@var{@b{true}/false}
        deletefstab=@var{@b{true}/false}
        force=@var{true/@b{false}}
        ifelapsed=@var{mins} 
        expireafter=@var{mins}

@end smallexample 
@end cartouche

@noindent
The options allow you to temporarily unmount a directory without actually
removing it from the filesystem table. The option @code{force} is not currently
implemented and will likely have to be system dependent.
For example:

@smallexample
unmount:

   physics::

      libraryserver:/$(site)/libraryserver/data

@end smallexample

@noindent
If the device is busy then the actual unmount will not take place until
it becomes free, or the machine is rebooted.  This feature should work
on AIX systems, in spite of these machines inherent peculiarities in the
form of the filesystem table.

Some users do not mount filesystems on a directory of the same name as the
source directory. This can lead to confusion.
Note, if you have problems removing a mounted filesystem, try using
the mountpoint of the filesystem, rather than the name of the filesystem itself,
in the unmount command.


@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@node Cfservd.conf and cfrun reference, Cfexecd reference, Cfagent reference, Top
@chapter Cfservd and cfrun reference

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@menu
* cfservd control::             
* admit grant and deny::        
* cfrun::                       
* Firewalls and NATs::          
@end menu


The server daemon is controlled by a file called
@file{cfservd.conf}.
@cindex @file{cfservd.conf} file
The syntax of this configuration file is deliberately modelled on
cfengine's own configuration file, but despite the similarities, they are separate.

You can use @code{groups} and @code{import} in both files
to break up files into convenient modules and to import
common resources, such as lists of groups.
    
Note that the classes in the @file{cfservd.conf} file do not tell you the
classes of host which have access to files and directories, but rather
which classes of host pay attention to the access and deny commands when
the file is parsed.

Authentication is not by class or group but by hostname, like
the @file{/etc/exports} file on most Unix systems. The syntax for the
file is as follows:

@cartouche

@w{}
@smallexample

 control:

   @var{classes}::

       domain = ( @var{DNS-domain-name} )

       cfrunCommand = ( "@var{script/filename}" )  # Quoted

       MaxConnections = ( @var{maximum number of forked daemons} )

       # ChecksumDatabase = ( @var{filename} ) - deprecated

       IfElapsed = ( @var{time-in-minutes} )

       DenyBadClocks = ( @var{false} )

       AllowConnectionsFrom = ( @var{IP numbers} )

       DenyConnectionsFrom = ( @var{IP numbers} )

       AllowMultipleConnectionsFrom = ( @var{IP numbers} )

       TrustKeysFrom  = ( @var{IP numbers} )

       AllowUsers = ( mark systemuser )

       LogAllConnections = ( @var{false/true} )

       LogEncryptedTransfers = ( @var{false/true} )

       SkipVerify = ( @var{IP numbers} )

       DynamicAddresses = ( @var{IP numbers} )

       BindToInterface = ( @var{IP number}/@var{hostname} )

       HostnameKeys = ( @var{true/false} )

 groups:

   @var{Group definitions}

 import:

   @var{Files to import}

 admit: | grant:

   @var{classes}::

      /@var{file-or-directory}

        @var{wildcards/hostnames}

 deny:

   @var{classes}::

      /@var{file-or-directory}

        @var{wildcards/hostnames} root=@var{hostlist} encrypt=@var{true/on}

@end smallexample

@end cartouche

@cindex Iteration in server rules
@cindex cfservd.conf iteration
Iteration of variables is allowed, hence:
@noindent

@w{}
@smallexample
	control:
	  Split = ( " " )
	  hostlist = ( "10.10.10.1 10.10.10.2 10.10.10.3" )  
	  dirs =  ( "bin etc lib" )
	  base = ( /usr )

	#########################################################

	admit:
	   $(base)/$(dirs)   $(hostlist)
@end smallexample
results in:

@smallexample
	Path: /usr/bin (encrypt=0)
	   Admit: 10.10.10.1 10.10.10.2 10.10.10.3 root=
	Path: /usr/etc (encrypt=0)
	   Admit: 10.10.10.1 10.10.10.2 10.10.10.3 root=
	Path: /usr/lib (encrypt=0)
	   Admit: 10.10.10.1 10.10.10.2 10.10.10.3 root=
@end smallexample

The file consists of a control section and access information.

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node cfservd control, admit grant and deny, Cfservd.conf and cfrun reference, Cfservd.conf and cfrun reference
@section control cfservd


@c ...........................................
@c SUBSECTION
@c ...........................................

@menu
* IP address ranges::           
* AllowConnectionsFrom::        
* AllowMultipleConnectionsFrom::  
* AllowUsers::                  
* AutoExecCommand::             
* AutoExecInterval::            
* BindToInterface in cfservd::  
* ChecksumDatabase in cfservd::  
* cfrunCommand::                
* DenyBadClocks::               
* DenyConnectionsFrom::         
* cfservd HostnameKeys::        
* cfservd IfElapsed::           
* LogAllConnections::           
* LogEncryptedTransfers::       
* MaxConnections::              
* TrustKeysFrom::               
* DynamicAddresses::            
@end menu

@c ...........................................
@c SUBSECTION
@c ...........................................


@node IP address ranges, AllowConnectionsFrom, cfservd control, cfservd control
@subsection IP address ranges

In the access control lists below, host ranges can be specified in a
number of ways i) as substrings, ii) as address ranges denoted by the
"-" hyphen, or iii) as CIDR (Classless Inter Domain Routing) notation.
For example

@smallexample
128.39.73
128.39.74.10/23
128.39.74-75.10-22
2001:700:700:3:290:27ff:fea2:4730-4790
2001:700:700:3:290:27ff:fea2:4730/64
@end smallexample
In the CIDR notation, the slash followed by a number indicates the
netmask, or the number of bits which are common to a group of hosts.
Normally, this is connected to a specific subnet, but here it simply
represents the number of bits from the left which are fixed for matching;
all remaining bits are wildcards.
The following forms are equivalent:

@smallexample
128.39.74.
128.39.74.10/24
128.39.74.1-254
@end smallexample

@c ...........................................
@c SUBSECTION
@c ...........................................


@node AllowConnectionsFrom, AllowMultipleConnectionsFrom, IP address ranges, cfservd control
@subsection AllowConnectionsFrom
This variable allows a list
of numerical IP masks to be specified, which cfservd will allow connections from.
If the list is not empty and a host whose IP address is not specified
attempts to connect to the daemon, its connection will be closed
immediately.
  This can be used to prevent hanging connection attacks from malicous
hosts and other denial of service attacks which would bind thread
resources.

@smallexample
     control:

      AllowConnectionsFrom = ( 128.39.89  192.2.0.10 )

@end smallexample
@cindex @code{AllowConnectionsFrom} variable
@mbindex Hanging connections attacks
@mbindex Denial of service attacks

@c ...........................................
@c SUBSECTION
@c ...........................................


@node AllowMultipleConnectionsFrom, AllowUsers, AllowConnectionsFrom, cfservd control
@subsection AllowMultipleConnectionsFrom

This variable should contain a list of IP wildcards to hosts which are
allowed simultaneous sessions on the server. Hosts which are not in this
list are allowed to connect only once, i.e. they must terminate and
reconnect in order to establish a new session. This is to prevent a
possible attacker from opening multiple sockets and never closing them,
resulting in a denial of service attack. Hosts IP's can be placed here
if they could have overlapping copy sessions (e.g. long backup transfers
which can run over time). This prevents the error message "Multiple
connections denied/spam shield".

@c ...........................................
@c SUBSECTION
@c ...........................................


@node AllowUsers, AutoExecCommand, AllowMultipleConnectionsFrom, cfservd control
@subsection AllowUsers

This list determines which users are to be allowed to connect to the daemon.
Note that there is no way of identifying users except by their public keys.
If a malicious asserts their identity, when no public key for the named
user is known to the server, then they could spoof the identity of that
user.  All users who should be allowed to connect need to be here.
This applies to use of cfrun.
@cindex cfrun, limiting users on server
@cindex Key security of users

@w{}
@smallexample

AllowUsers = ( mark root )

@end smallexample

In other words, this is a "security by obscurity" first defence against
picking up bad keys, when the server is in trust mode, with respect to a
host. The attacker must know a valid user name in order to even try
their luck entering into a key dialogue.

This reduces the probability that spoofing can be successful. The only
real defence against spoofing is to make sure that all required public keys
are installed in advance, and to switch off trust.

@vindex AllowUsers
@cindex AllowUsers in cfservd

@c ...........................................
@c SUBSECTION
@c ...........................................


@node AutoExecCommand, AutoExecInterval, AllowUsers, cfservd control
@subsection AutoExecCommand
This variable no longer exists in cfengine version 2.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node AutoExecInterval, BindToInterface in cfservd, AutoExecCommand, cfservd control
@subsection AutoExecInterval
This variable no longer exists in version 2 of cfengine.
@cindex @code{AutoExecInterval} variable



@c ...........................................
@c SUBSECTION
@c ...........................................

@node BindToInterface in cfservd, ChecksumDatabase in cfservd, AutoExecInterval, cfservd control
@subsection BindToInterface in cfservd

If this is set to a specific IP address of an IP configured interface,
cfservd will listen for connections only on that interface. On Multi-homed
hosts this allows one to restrict the traffic to one interface. Note, Unix
only allows one or all interfaces to be selected. An interface must be
configured with an IP address in order to be bound.
@cindex Multihomed hosts
@vindex BindToInterface
@cindex Binding to one interface only

@c ...........................................
@c SUBSECTION
@c ...........................................

@node ChecksumDatabase in cfservd, cfrunCommand, BindToInterface in cfservd, cfservd control
@subsection ChecksumDatabase in cfservd

(This variable is deprecated as of version 2.1.21. The location of the
database will be fixed internally.)

This is the path and filename to a database which will cache
MD5 checksum values server-side. This optimization is only available
if you have the Berkeley database library @samp{libdb} on your
system. If this variable is not defined, no database caching
will be used and checksum values will be computed directly on
request. The utility of this solution is a trade-off between
the time it takes to compute the checksum versus the time
for a disk-based lookup.
@cindex @code{ChecksumDatabase} variable
@mbindex MD5 checksums take a long time to compute.
@mbindex Checksums take too long to compute.



@c ...........................................
@c SUBSECTION
@c ...........................................


@node cfrunCommand, DenyBadClocks, ChecksumDatabase in cfservd, cfservd control
@subsection cfrunCommand

This string is the command which you would like to be executed
remotely by the @code{cfrun} command. Note that you must, in addition,
authorize access to this file in the @code{admit} section. The access
rule should (as usual) be to the actual file object path, not
including any symbolic links.

@cindex @code{cfrunCommand} variable

@c ...........................................
@c SUBSECTION
@c ...........................................

@node DenyBadClocks, DenyConnectionsFrom, cfrunCommand, cfservd control
@subsection DenyBadClocks
If this is set to @code{off}, cfservd will not deny access to clients whose
clocks are off by more than one hour. The default is to deny access to
systems whose clocks differ by more than one hour. This can prevent
messages of the form `Can't stat' file when remote copying.
@cindex @code{DenyBadClocks} variable
@mbindex Can't stat error when remote copying


@c ...........................................
@c SUBSECTION
@c ...........................................

@node DenyConnectionsFrom, cfservd HostnameKeys, DenyBadClocks, cfservd control
@subsection DenyConnectionsFrom

Hosts which are included by the allow-list above can be explicitly
denied access using this list.

@smallexample
     control:

      DenyConnectionsFrom = ( 128.39.89.76 )  # rogue host

@end smallexample
@cindex @code{DenyConnectionsFrom} variable

@c .....................................................
@c SUBSECTION
@c .....................................................

@node cfservd HostnameKeys, cfservd IfElapsed, DenyConnectionsFrom, cfservd control
@subsection HostnameKeys in cfservd

If this variable is set to true/on, it causes cfservd to
lookup and store trusted public keys according to their
DNS fully qualified host name, instead of using the IP address.
This can be useful in environments where hosts do not have fixed
IP addresses, but do have fixed hostnames.

@smallexample

  HostnameKeys = ( on )

@end smallexample
This method of storing keys is not recommended for sites with
fixed IP addresses, since it removes one security barrier
from a potential attacker by potentially allowing DNS spoofing.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node cfservd IfElapsed, LogAllConnections, cfservd HostnameKeys, cfservd control
@subsection IfElapsed in cfservd

The @code{IfElapsed} anti-spamming filter is also built into
@code{cfservd} so that a remote user cannot even get as far as
causing cfengine to parse its input files (which could
be used for spamming in itself). The time is in minutes,
the default is one hour.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node LogAllConnections, LogEncryptedTransfers, cfservd IfElapsed, cfservd control
@subsection LogAllConnections

If set to true, every successful connection will be logged to syslog.
This could be useful for identifying abuses of the service, if the server
should come under attack, e.g. a denial of service attack. The IP address
can then be excluded from the allowed connections list.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node LogEncryptedTransfers, MaxConnections, LogAllConnections, cfservd control
@subsection LogEncryptedTransfers

If set to true, every successful request for a file that is granted
access only with an encrypted connection is logged in syslog.

@c ...........................................
@c SUBSECTION
@c ...........................................

@node MaxConnections, TrustKeysFrom, LogEncryptedTransfers, cfservd control
@subsection MaxConnections
This integer value sets a limit on the maximum number of
child daemon threads which cfservd will `fork' in order
to handle remote requests. The default value is ten.
@cindex @code{MaxConnections} variable


@c ...........................................
@c SUBSECTION
@c ...........................................

@node TrustKeysFrom, DynamicAddresses, MaxConnections, cfservd control
@subsection TrustKeysFrom

Hosts which are included in this list are automatically
trusted, if cfservd does not know their public key. This
allows public keys to be exchanged. Cfservd will not automatically
accept a public key from a host it does not know, since the
key will be used to assert strong authentication later.
Once a public key has been associated with an IP address, it
will never be updated, unless the existing key is deleted by hand.

@smallexample
     control:

      TrustKeysFrom = ( 128.39.89.76 )     # trusted host
      TrustKeysFrom = ( 128.39.89.76/24 )  # trusted subnet

@end smallexample
@cindex @code{TrustKeysFrom} variable


@c ...........................................
@c SUBSECTION
@c ...........................................

@node DynamicAddresses,  , TrustKeysFrom, cfservd control
@subsection DynamicAddresses

Hosts which are included in this list are assumed to have IP addresses which
can change with time, e.g. hosts which are given IP addresses by DHCP
or a BOOTP like protocol.
@cindex DHCP addresses

@smallexample
     control:

      DynamicAddresses = ( 128.39.74.100-200 )  # DHCP range

@end smallexample
@cindex @code{DynamicAddresses} variable

If cfservd receives a connection from an IP address that is in this list,
and trustkey is @emph{true}, the existing key for that IP address can be
replaced with a new key, and the old key is recorded in a "used keys"
list, access is granted. If trust is switched off, the server looks
in the "used key list" to see if the key has been seen before. If not
access is refused. If it has been seen before -- it uses this earlier
trust to accept the connection and replace the IP-key binding.
@cindex DHCP
@cindex Dynamic addresses

Note that used keys are kept in a database for easy lookup, whereas
fixed keys are kept in files for easy administration. If host keys
change or are reinstalled on the dynamically allocated hosts, then
this database should probably be deleted to purge keys that become
illegal.

DHCP addresses have no effect on hosts that use IPV6, since IPV6 addresses
are generally issued based on an interface MAC address and do not therefore
change.
@cindex IPV6 and DHCP

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node admit grant and deny, cfrun, cfservd control, Cfservd.conf and cfrun reference
@section admit, grant and deny

@c ...........................................
@c SUBSECTION
@c ...........................................

@menu
* root=::                       
* encrypt=::                    
* SkipVerify::                  
@end menu

@node root=, encrypt=, admit grant and deny, admit grant and deny
@subsection @code{root=}
This list specifies the names of hosts which are to have read
access to files, regardless of the owner of the file. This effectively
gives root users on connecting hosts privileges to non-root owned
files on the server, but not vice-versa, similar to the NFS root mapping,
except that there is no question of a client being able to modify files
on the server. Caution: cfservd trusts the DNS service, so be aware that
cache poisoning attacks are a possible way of bypassing access controls.

@b{Cfservd requires you to grant access to files without following any symbolic
links. You must grant access to the real file or directory in order to access
the file object.} This is a security feature in case parties with login access
to the server could grant access to additional files by having the permission
to create symbolic links in a transitory directory, e.g. @file{/tmp}.
@cindex Symbolic links in admit
@cindex Links in access control
@cindex Access control by directory
@cindex Access control and symlinks

As of version 2.0.4: Once a verified host address has been identified with a functioning
public/private key authentication, the IP address is added to the SkipVerify
list, so that time is not wasted in verifying reverse lookups, when the
identify can be verified more efficiently and securely by a key mechanism.
@cindex SkipVerify and public-private keys
@cindex Caching of reverse lookups
@cindex Reverse lookup and SkipVerify
@vindex SkipVerify

@c ...........................................
@c SUBSECTION
@c ...........................................

@node encrypt=, SkipVerify, root=, admit grant and deny
@subsection @code{encrypt=true}
If this option is set, cfservd will only serve the named files
if the copy access type is @code{secure}, i.e. on an encrypted
link. This presupposes that cfengine has been compiled with
a working OpenSSL library.


@c ...........................................
@c SUBSECTION
@c ...........................................

@node SkipVerify,  , encrypt=, admit grant and deny
@subsection SkipVerify

If connecting hosts use a Network Address Translator in order to share an IP address,
reverse lookup will fail to give a correct verification of host identity.
You can switch off cfservd's verification of IP host identity for specific IP addresses
or patterns using this command. E.g.

@smallexample

SkipVerify = ( 192.0.0.10  192.0.2.  )

@end smallexample

This does not affect key verification.

NOTE!! This is a security risk because it means that cfservd implicitly
trusts the connecting hosts! You should be very careful in using
Network Address Translators in a secure environment. It is not recommended
for sites which require a high level of security.
@cindex Network Address Translators
@cindex Security risk




@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node cfrun, Firewalls and NATs, admit grant and deny, Cfservd.conf and cfrun reference
@section @code{cfrun}

The general syntactic form of the @code{cfrun} command is

@cartouche

@w{}
@smallexample

  cfrun -@var{option} --@var{longoption} @var{class1} @var{class2 ...}

@end smallexample
@end cartouche

@noindent
Since @code{cfrun} addresses remote hosts, there is an ambiguity in
whether options are intended for the @code{cfrun} command itself, on the local
host, or whether they are to be passed on to the agent on the remote hosts.
To clarify this distinction, the arguments are organized as follows:

@cartouche

@w{}
@smallexample

  cfrun -@var{local options} -- @var{remote options} -- @var{remote classes}

@end smallexample
@end cartouche

@noindent
Local options are processed by @code{cfrun} on the local host; remote options
are passed on as options to the remote @code{cfagent} (actually to the
command defined in @code{cfrunCommand} in the file @file{cfservd.conf};
remote classes are processed by the remote @code{cfservd} service, and specifiy
classes which must be satisfied by the remote host in order to invoke the
remote command.


The @samp{-q} and @samp{-I} options are
always assumed when executing cfengine remotely, so that @code{SplayTime} is
effectively zero when polling hosts serially, and the output always
shows what is happening on the remote hosts.
@cindex SplayTime in cfrun

@cindex @samp{-T} in cfrun.
@cindex Trust, key exchange with cfrun
On connecting to a remote host, cfengine attempts to obtain credentials
by exchanging keys. Unknown keys, in a key exchange, need to be explicitly
accepted on trust. Normally, the interactive @code{cfrun} program prompts
the user explicitly, (like in the secure shell, @code{ssh}, connections).
This can be annoying if there are many hosts to connect to.
The @samp{-T} option tells cfengine to trust all new keys. This option
should be used with caution, and only at times when one is sure that the
hosts one is connecting to are trustworthy.

Each host evaluates the classes sent by @code{cfrun}
and decides whether cfengine should be invoked.
@cindex Running @code{cfrun}
Only hosts which belong to the classes defined on the @code{cfrun}
command line are executed. This allows you to single out groups of hosts
which should execute cfengine, based on the very classes which you have
defined for your configuration.  If no classes are sent on the command
line, then all hosts are run.

@code{cfrun} uses a configuration file which is located under the
@code{CFINPUTS} directory in order to determine which hosts and in
which order it should try to connect. Because cfengine always uses a
reliable TCP protocol for connections, it verifies each connection
rather than simply broadcasting openly. Using this file you can even
simulate broadcasting to hosts outside your subnet.
@cindex Broadcasts to the cfengine service.

This file should contain every host name you ever want to
configure remotely, because you can still select subsets of
the file by specifying classes which the remote host will understand.
If the remote host is not in one of the classes you specify when you
run @code{cfrun}, then it will simply ignore the request. Conversely,
if you do not place a host in this file, it will never be contacted
when you use the @code{cfrun} command. The format of the file
is as follows

@cartouche

@w{}
@smallexample

 #
 # Comment ..
 #
 domain=@var{my.domain}
 access=@var{user1},@var{user2}
 outputdir=@var{directory}
 maxchild=@var{number limit}
 hostnamekeys=@var{true/false}
 bindtointerface=@var{IP address}

 @var{hostname1}            @var{options}
 @var{hostname2}:@var{port} @var{options}
 ...
 include=cfrun.site1.external.hosts
 include=cfrun.site1.internal.hosts
 include=cfrun.site2.private.hosts
 include=cfrun.site2.shared.hosts
 
@end smallexample
@end cartouche
@cindex hostnamekeys
@cindex include in cfrun

@noindent
If the option @code{outputdir} is present, cfrun forks a separate
process for each host and passes the output to files in a named directory.
The @code{maxchild} line limits the number of forked processes.

It is important to add the domain-name to this file.
The options you specifiy in this file, per host, are added to those
you might specify on the command line when invoking cfengine remotely.
For instance, you might know of a bug on one host and decide not to
perform interface configuration on that one machine. You would write
a line like this:

@smallexample

  funny.domain -- -i  # problem host

@end smallexample

@cindex Running cfengine from a single master host
@cindex Running cfengine from a single master host
You could use @code{cfrun} inside one of your cfengine configuration
files in order to remotely execute cfengine on all of the other network
machines, by setting up a host list. The disadvantage however is that
cfengine has to poll the systems on the network, which means that
cfengine cannot be working in parallel on all hosts.

Some other examples:

@smallexample

e.g.  cfrun -- -- linux          Run on all linux machines
      cfrun -- -p                Ping and parse on all hosts
      cfrun -v -- -p             Ping all, local verbose
      cfrun -v -- -k -- solaris  Local verbose, all solaris, but no copy

@end smallexample

Amongst the local options, one may specify a subset of the hosts which are to
be contacted by cfrun, i.e. to avoid processing the entire list of hosts. For
example, to contact only host1 and host2, given that they are already in
the list of hosts.

@smallexample

cfrun -v host1 host2
cfrun -v host1 host2 -- -p 

@end smallexample
@cindex Contacting specific hosts with cfrun

@node Firewalls and NATs,  , cfrun, Cfservd.conf and cfrun reference
@section Firewalls and NATs

Firewalls and Network Address Translators (NAT) can be a problem for
addressing.  Suppose you have a firewall and with a private IP-range
behind the firewall.  You want to update the nodes from a central
host. You can do a two stage configuration: first update the firewall and
then update from the firewall to the nodes.
 
But suppose you already use SNAT (Source Network Address Translation) and DNAT
(Destination ...) for the nodes. With DNAT you can say that socket 22000
on the firewall is routed to @var{host-name}:5308. DNAT gives us the
possibilty to update the nodes from a central server in one step instead
of two.
 
If the port command is given cfrun uses this to connect to the client
instead of the default (5308) one.
Here is an example (@file{cfrun.hosts}): 

@smallexample 
domain=example.org
access=mark,sigmund
hostnamekeys=true

node1.example.org
node2.example.org:22000 -DNis
node2.example.org:22001
 
@end smallexample
@cindex HostnameKeys

This connects to: 1) node1 with standard port, 2) node2 with port 22000 and extra options -DNis
and, 3) node2 with port 22000.

@cindex NAT
@cindex Network address translator
@cindex Changing cfengine port
@cindex Port, connecting to different

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@node Cfexecd reference, Problem solving, Cfservd.conf and cfrun reference, Top
@chapter Cfexecd reference

In wrapper mode (non-forking, non-daemon mode), cfagent is run by adding a
line to the root crontab file of each system:

@smallexample
0,30 * * * * /usr/local/sbin/cfexecd -F
@end smallexample

This is enough to ensure that cfengine will get run. Any output generated
by this job, will be stored in @file{/var/cfengine/outputs}.
 
The program @code{cfexecd} operates as a wrapper for cfagent.  It has the
following options:

@smallexample
-h (--help)
-d (--debug)
-v (--verbose)
-q (--no-splay)
-F (--no-fork)
-1 (--once)
-g (--foreground)
-p (--parse-only)
-L (--ld-library-path)
@end smallexample

@cindex /var/cfengine/output
@vindex /var/cfengine/output
@cindex Output logs
In addition, if you add the following to the file @file{cfagent.conf},
the system administrator will be emailed a summary of any output:

@smallexample

control:

smtpserver    = ( mailhub.example.org ) # site MTA which can talk smtp
sysadm        = ( mark@@example.org )   # mail address of sysadm
EmailMaxLines = ( @var{n} )             # max lines of output to email
OutputPrefix  = ( "!" )                 # Line prefix

@end smallexample

@noindent
Fill in suitable values for these variables. @code{EmailMaxLines} may
be set to 0 to disable email output, a postive integer to set a limit,
or @code{inf} to email the whole output regardless of its size. If
undefined, @code{EmailMaxLines} defaults to 100.

@cindex Mailing output
@vindex smtpserver
@vindex sysadm
@vindex EmailMaxLines
@cindex cfexecd
An alternative, or additional way to run cfengine, is to run the @file{cfexecd}
program is daemon mode (without the @samp{-F}) option. In this mode, the daemon
lives in the background and sleeps, activating only in accordance with
a scheduling policy. The default policy is to run once every hour (equivalent
to @code{Min00_05}). Here is how you would modify @file{cfagent.conf} in
order to make the daemon execute cfagent every half-hour:

@smallexample
  control:

   # When should cfexecd in daemon mode wake up the agent?

   schedule   = ( Min00_05 Min30_35 )
@end smallexample
Note that the time specifications are the basic cfengine @emph{time classes}.
Although one of these methods should suffice,
no harm will arise from running both cron and the cfexecd side-by-side.
Locking mechanisms are used by @code{cfagent} to ensure that no contention will occur.
@cindex Mailing output
@vindex smtpserver
@vindex sysadm
@cindex cfexecd

Note, that if problems with library path for compiled-in libraries occur, an
explicit library path can be specified with the @samp{-L} option.

@smallexample
0,30 * * * * /usr/local/sbin/cfexecd -F -L /local/iu/lib:/local/lib:/local/gnu/lib
@end smallexample


The output generated by a cfagent run is collected and stored with
date stamps in the @file{outputs} subdirectory of the work directory
(usually @file{/var/cfengine/outputs}). If cfengine has a valid smtp
server configured it will attempt to E-mail new reports to the system
administrator.  Duplicate reports are suppressed however for a period
of one day. Thus, if one has a repeating message, then it will only be
sent by E-mail once per day -- this feature is meant to prevent
cfagent from spamming administators with multiple, indentical reports.
As soon a report different from the previous one is received, the
memory is reset.

Note: this repeated message suppression feature cannot work if you include
time dependent data in messages, i.e. if you include the date or time in an
alert, then clearly the message will be a different message each time. Output
from cfengine should not contain the time or date, except in the E-mail header.


@cindex Mail from cfexecd
@cindex Spam suppression

@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@node Problem solving, Example configuration file, Cfexecd reference, Top
@chapter Problem solving



@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@menu
* cf.preconf bootstrap file::   
* cfrc resource file::          
@end menu

@node cf.preconf bootstrap file, cfrc resource file, Problem solving, Problem solving
@section cf.preconf bootstrap file
@cindex cf.preconf bootstrap file
@vindex cf.preconf
@cindex Bootstrap file
@cindex Deadlock
@cindex Hung machine

In some cases you will want to run cfengine on a system to configure it
from scratch.  If the system is in a very bad way, it might not even be
able to parse the cfengine configuration file, perhaps because the
network was not properly configured or the DNS (Domain Name Service) was
out of action.  To help prevent this situation, cfengine looks for a
script called @code{cf.preconf} which gets executed prior to parsing and
can be used to perform any emergency tests.  This file needs only
contain enough to get the system to parse the configuration files.

@code{cf.preconf} may be any script in any language.  It need not exist
at all! It is fed one argument by cfengine, namely the system hard-class
for the current system (e.g.  @code{ultrix}).  Here is an example:

@smallexample
#!/bin/sh 
#
# cf.preconf is an emergency/bootstrap file to get things going
# in case cfengine is unable to parse its config file
#

backupdir=/iu/nexus/local/iu/etc

 #
 # If these files don't exist, you might not be able to parse cfagent.conf
 #

if [ ! -s /etc/resolv.conf ]; then

 echo Patching basics resolv.conf file
 cat > /etc/resolv.conf << XX
domain iu.hioslo.no
nameserver 128.39.89.10
XX

fi

#
# SVR4
#

if [ "$1" = "solaris" ]; then

  if [ ! -s "/etc/passwd" ]; then
 
  echo Patching missing passwd file
    /bin/cp $backupdir/passwd /etc/passwd
  fi

  if [ ! -s "/etc/shadow" ]; then
    
   echo Patching missing passwd file
   /bin/cp $backupdir/shadow /etc/shadow
  fi 
fi

#
# BSD 4.3
#
 
if [ "$1" = "linux" ]; then

   if [ ! -s "/etc/passwd"  ]
   then
    
    echo Patching missing passwd file
    /bin/cp $backupdir/passwd.linux /etc/passwd
   fi
fi

@end smallexample 

@cindex /etc/host.conf
@vindex /etc/host.conf
@cindex -x option
@vindex -x option

Note - in some circumstances, it might be appropriate to exit cfengine
altogether after this script. If the script outputs a string containing
the text "cfengine-preconf-abort", then cfagent will abort execution
immediately after this.

@cindex Emergency abort
@cindex Abort cfengine after cf.preconf

@c -------------------------------------------------------------------------------
@c SECTION
@c -------------------------------------------------------------------------------

@node cfrc resource file,  , cf.preconf bootstrap file, Problem solving
@section cfrc resource file
@cindex cfrc resource file
@cindex Resource file
@vindex cfrc

If, for some reason you are not satisfied with the defaults which
cfengine uses, then you can change them by making an entry in the
resource file.  The default values are defined in the source code file
@code{classes.c} in the distribution.  The format of the resource file
is:

@smallexample
hardclass.variable: value
@end smallexample 

@noindent
For example, you might want to forget about where your HPUX system
mounts its mail directory and mount it under @code{/usr/spool/mail}.  In
this case you would add the line:

@smallexample
hpux.maildir: /usr/spool/mail
@end smallexample 

@noindent
To redefine the filesystem table for GNU/linux, you would write:

@smallexample
linux.fstab: /etc/linuxfstab
@end smallexample 

@noindent
The full list of re-definable resources is:

@smallexample
   mountcomm       # command used to mount filesystems
   unmountcomm     # command used to unmount filesystems
   ethernet        # name of the ethernet device
   mountopts       # options to above mount command
   fstab           # the name of the filesystemtable
   maildir         # the location of the mail directory
   netstat         # the full path to netstat and options
   pscomm          # the path to the system's ps command
   psopts          # the options used by ps (default aux/ef)
@end smallexample 

You should never need to redefine resources unless you decide to do something
non-standard.  Interested readers are referred to the values in @code{classes.c}.


@cindex Adding new classes
@cindex Support for new systems
@cindex New systems, support for

Cfengine is easily extensible so as to support a variety of
architectures.  You can even add your own.  To do so you need, first of
all, to define a new class for the operating system concerned.  The file
@emph{classes.c} has been separated off from the remainder of the source
code so that you can easily see which data structures need to be
extended.

To make life as straightforward as possible, three unused classes have
been defined.  They are called (unremarkably) @emph{unused1},
@emph{unused2} and @emph{unused3}.  If you add any further classes, it
will be necessary to increase the constant @emph{clssattr} defined in
@emph{cf.defs.h} by one for every new addition.  You do not need to
change @emph{clssattr} if you simple replace one of the unused classes
by a real class.

To see fully the impact of what you need to do, you should make a search
for the strings @emph{unused?} in all of the source files.  Certain
special cases need to be handled for each operating system.  For
example, the form of the filesystem table is quite radically different
on some systems such as AIX.  One thing you must do is to fill in the
default values for the new operating system in the file
@emph{classes.c}.

If you fill in the details for a new operating system before it finds
its way into a new release, you might consider sending the details to
the bug list in the next paragraph.




@c **********************************************************************
@c CHAPTER
@c **********************************************************************

@node Example configuration file, Variable Index, Problem solving, Top
@chapter Example configuration files
@cindex Example configuration files

Here is a sample from a large configuration file, just to give you
some ideas. The file is broken up into manageable pieces for
convenience.

@menu
* cfagent.conf::                
* cf.groups::                   
* cf.main::                     
* cf.site::                     
* cf.motd::                     
* cf.users::                    
* cf.solaris::                  
* cf.linux::                    
* cf.freebsd::                  
* cfservd.conf::                
@end menu

@c .....................................................
@c SECTION
@c .....................................................

@node cfagent.conf, cf.groups, Example configuration file, Example configuration file
@section cfagent.conf
@cindex @file{cfagent.conf}

@w{}
@smallexample
#####################################################################
# 
#  CFENGINE CONFIGURATION FOR site = iu.hioslo.no
#
#  This file is for root only.
#
######################################################################

###
#
# BEGIN cfagent.conf
#
###

import:

   #
   # Split things up to keep things tidy
   #

   any::            
                    cf.groups
                    cf.main
                    cf.site
                    cf.motd

   hpux::           cf.hpux
   linux::          cf.linux
   solaris::        cf.solaris
   sun4::           cf.sun4
   ultrix::         cf.ultrix
   freebsd::        cf.freebsd

   #
   # Do you want to do this ?
   #

   AllHomeServers:: cf.users


###
#
# END cfengine.conf
#
###
@end smallexample

@c .....................................................
@c SECTION
@c .....................................................

@node cf.groups, cf.main, cfagent.conf, Example configuration file
@section cf.groups
@cindex @file{cf.groups}

@w{}
@smallexample
##############################################################
#
# cf.groups - for iu.hioslo.no
#
# This file contains  all group/class definitions
#
#################################################################

###
#
# BEGIN cf.groups
#
###

groups:

   #
   # Define some groups
   #
 
   iu = ( nexus ferengi regula borg dax lore axis worf daystrom voyager 
          aud1 aud2 aud3 aud4 bajor ds9 takpah takpeh nostromo galron
          thistledown rama chaos pc-steinarj pc-hildeh way jart kosh )

   diskless   = ( regula ferengi lore )

   standalone = ( nexus axis dax borg worf daystrom voyager 
                  aud1 aud2 aud3 aud4 bajor ds9 takpah takpeh
                  nostromo galron thistledown rama pc-torejo
                  pc-steinarj pc-hildeh )

   AllHomeServers   = ( nexus )
   AllBinaryServers = ( nexus borg )

   XBootServer  = ( nexus )
   WWWServers   = ( nexus )
   FTPserver    = ( nexus )
   NameServers  = ( nexus )
   PasswdServer = ( nexus )
   BackupHost   = ( nexus )

   MailHub      = ( nexus )
   MailClients  = ( iu -nexus )

###
#
# END cf.groups
#
###

@end smallexample

@c .....................................................
@c SECTION
@c .....................................................

@node cf.main, cf.site, cf.groups, Example configuration file
@section cf.main
@cindex @file{cf.main}

@w{}
@smallexample
##############################################################
#
# cf.main - for iu.hioslo.no
#
# This file contains generic config stuff
#
#################################################################

###
#
# BEGIN cf.main
#
###

control: 

   access    = ( root )        # Only root should run this

   site      = ( iu )
   domain    = ( iu.hioslo.no )
   sysadm    = ( drift@@iu.hioslo.no ) 

   repository = ( /var/spool/cfengine )

   netmask   = ( 255.255.255.0 )
   timezone  = ( MET )
   nfstype   = ( nfs )

   sensiblesize  = ( 1000 )
   sensiblecount = ( 2 )
   editfilesize  = ( 20000 )

   mountpattern = ( /$(site)/$(host) )
   homepattern  = ( u? ) 

   #
   # If we undefine this with cfengine -N longjob
   # then we switch off all jobs labelled with this class
   #

   addclasses = ( longjob )

   #
   # Macros & constants are inherited downwards in imports
   # but are not passed up to parent files. Good idea to
   # define them all here
   #

   masterfiles = ( /iu/nexus/local/iu )
   main_server = ( nexus )
   cfbin       = ( /iu/nexus/local/gnu/lib/cfengine/bin )
   gnu         = ( /local/gnu )
   ftp         = ( /local/iu/ftp )
   nisslave    = ( dax )
   nisfiles    = ( /iu/nexus/local/iu/etc )

   #
   # The action sequence for daily (full) runs and
   # for hourly updates (called with -DHourly)
   #

   Hr00::

      actionsequence = 
         (
         copy
         mountall
         mountinfo
         checktimezone
         netconfig
         resolve
         unmount
         shellcommands
         addmounts
         links.Prepare
         files.Prepare
         directories
         links.Rest
         mailcheck
         mountall
         required
         tidy
         disable
         editfiles
         files.Rest
         processes
         )

   !Hr00::

      actionsequence =
         (
         resolve
         shellcommands
         copy
         editfiles
         processes
	 links
         )

   force::

      actionsequence = 
         (
         files.Prepare.Rest
         tidy
         )

######################################################################

homeservers:

   iu:: nexus

binservers:

   iu.solaris::                 nexus
   iu.linux::                   borg

mailserver:

   any:: nexus:/var/mail

mountables:

   any::
         nexus:/iu/nexus/u1
         nexus:/iu/nexus/u2
         nexus:/iu/nexus/u3
         nexus:/iu/nexus/u4
         nexus:/iu/nexus/u5
         nexus:/iu/nexus/u6
         nexus:/iu/nexus/ua
         nexus:/iu/nexus/ud
         nexus:/iu/nexus/local
         nexus:/opt/NeWSprint
         nexus:/opt/AcroRead
         borg:/iu/borg/local
         dax:/iu/dax/local

miscmounts:

   linux||freebsd::   nexus:/iu/nexus/local /iu/nexus/local ro

######################################################################

broadcast:

  ones

defaultroute:

   cadeler30-gw

######################################################################

resolve:

      128.39.89.10  # nexus
      158.36.85.10  # samson.hioslo.no
      129.241.1.99

######################################################################

tidy: 

   #
   # Some global tidy-ups
   #

      /tmp/                    pat=*             r=inf     A=1
      /var/tmp                 pat=*             r=inf     A=1
      /                        pat=core          r=1       A=0
      /etc                     pat=core          r=1       A=0

######################################################################

ignore:                       # Don't check or tidy these directories

      /local/lib/gnu/emacs/lock/
      /local/tmp
      ftp
      projects
      /local/bin/top
      /local/lib/tex/fonts
      /local/iu/etc
      /local/etc
      /local/iu/httpd/conf
      /usr/tmp/locktelelogic
      /usr/tmp/lockIDE
      RootMailLog

      #
      # Emacs lock files etc
      #

      !*
      /local/lib/xemacs

      #
      # X11 keeps X server data in /tmp/.X11
      # better not delete this!
      #

      .X11

      #
      # Some users like to give a file or two 777 protection here
      # so netsurfers can update a log or counter when running as
      # `nobody'
      #

      www

#####################################################################

disable:

   /etc/hosts.equiv
   /etc/nologin
   /usr/lib/sendmail.fc


###
#
# END cf.main
#
###

@end smallexample

@c .....................................................
@c SECTION
@c .....................................................

@node cf.site, cf.motd, cf.main, Example configuration file
@section cf.site
@cindex @file{cf.site}

@w{}
@smallexample
##############################################################
#
# cf.site - for iu.hioslo.no
#
# This file contains site specific data
#
#################################################################

###
#
# BEGIN cf.site
#
###

links:

   Prepare::

      /local     -> /$(site)/$(binserver)/local
      /usr/local -> /local

   dax::

      /iu/dax/local             +> /iu/nexus/local
      /projects                 -> /iu/dax/local/projects
      /iu/nexus/u1/sowille/data -> /iu/dax/scratch/data
 
   XBootServer::

      #
      # Set up a /local/tftpboot area where all X terminal
      # stuff will be kept.
      #

      /tftpboot                  -> /local/tftpboot
      /local/tftpboot/td/configs -> /local/tftpboot/td/examples/configs
      /etc/bootptab              -> /tftpboot/bootptab
      /tftpboot/usr/lib/X11/td   -> /tftpboot/td

   NameServers::

      /etc/named.boot -> /local/iu/named/named.boot

   MailHub::

      /etc/mail/sendmail.cf ->! /iu/nexus/local/mail/sendmail.cf

   MailClients.solaris::

      /etc/mail/sendmail.cf ->! /iu/nexus/local/mail/client.cf

   nexus::

	/local/bin +> /local/latex/bin
 
#############################################################

disable:

  #
  # We run Berkeley sendmail and the config files are
  # all under /iu/nexus/local/lib/mail
  #

    /etc/aliases

 WWWServers.Sunday::

   #
   # Disabling these log files weekly prevents them from
   # growing so enormous that they fill the disk!
   #

   /local/iu/httpd/logs/access_log   rotate=empty
   /local/iu/httpd/logs/agent_log    rotate=empty
   /local/iu/httpd/logs/error_log    rotate=empty
   /local/iu/httpd/logs/referer_log  rotate=empty

   #
   # CERT warning, security fix
   #

  any::

    /usr/lib/expreserve

  FTPserver.Sunday.Hr00::

   /local/iu/xferlog rotate=3

#################################################################

files:

  Prepare::

      /etc/motd              m=0644 r=0 o=root act=touch
      /.cshrc                m=0644 r=0 o=root act=touch

   PasswdServer::

      /local/iu/etc/passwd m=0644 o=root g=other action=fixplain
      /local/iu/etc/shadow m=0644 o=root g=other action=fixplain

   WWWServers.Rest::

      /local/iu/www                           m=775        g=www act=fixall r=inf
      /local/iu/httpd/conf                    m=664 o=root g=www act=fixall r=inf
      /local/iu/www/cgi-bin-public/count_file m=777 o=root g=www act=fixplain

   FTPserver::

      #
      # Make sure anonymous ftp areas have the correct
      # protection, or logins won't be able to read
      # files - or perhaps a security risk. This is
      # Solaris 2 specific...
      #

      $(ftp)/pub        mode=755 o=ftp  g=ftp  r=inf act=fixall
      $(ftp)/Obin       mode=111 o=root g=other      act=fixall
      $(ftp)/etc        mode=111 o=root g=other      act=fixdirs
      $(ftp)/usr/bin/ls mode=111 o=root g=other      act=fixall
      $(ftp)/dev        mode=555 o=root g=other      act=fixall
      $(ftp)/usr        mode=555 o=root g=other      act=fixdirs

   Prepare::

      /etc/shells mode=0644 action=touch

   AllBinaryServers.Rest.longjob::

     /local mode=-0002 r=inf owner=root,bin group=0,1,2,3,4,5,6,7,staff
            links=tidy action=fixall

     /local/iu/RootMailLog  m=0666 action=touch

   dax.Rest::

    /iu/dax/scratch        r=0 o=root mode=1777 action=fixall
    /iu/dax/local/projects r=0 o=root mode=755  action=fixdirs

   nexus::

    /local/mail/sendmail.cf o=root m=444 act=fixplain

    /iu/nexus/ua/robot/.rhosts o=robot m=600 act=touch
 
    /local/iu/named/pz         o=root  m=644 act=fixall r=1

    /local/latex/lib/tex/texmf/fonts  owner=root
                                      mode=1666
                                      recurse=inf
                                      action=fixall

#################################################################

tidy:

      #
      # Make sure the file repository doesn't fill up
      #

      /var/spool/cfengine pattern=*    age=3

      /var                pattern=core age=0  r=inf
      /var/spool/mqueue   pattern=*    age=14 type=mtime

   BackupHost::

      # Here we tidy old backup tar files from the backup area
      # A special tmp area gets cleared every 4 days. The files
      # are created by Audun's backup help script (see shellcommands)

      /iu/nexus/backup1      pat=*  age=7

#################################################################

shellcommands: 

   PasswdServer::

      # Build and install the BSD compatible passwd file
      # from the master passwd/shadow file on Solaris

      "/local/iu/bin/BuildPasswdFiles"
      "/local/iu/bin/BuildGroupFiles"

  BackupHost.Sunday.Hr00|BackupHost.Wednesday.Hr00::

      #
      # Make a system backup of /iu/nexus/u? with Audun's script
      #

      "$(cfbin)/cfbackup -p -f /iu/nexus/backup1 -s /iu/nexus/ud"
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup1 -s /iu/nexus/ua"
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup1 -s /iu/nexus/u1"
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup1 -s /iu/nexus/u2" 
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup2 -s /iu/nexus/u3"
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup2 -s /iu/nexus/u4" 
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup2 -s /iu/nexus/u5" 
      "$(cfbin)/cfbackup -p -f /iu/nexus/backup2 -s /iu/nexus/u6" 

  nexus.Sunday.longjob.Hr00::

      #
      # See how much rubbish users have accumulated each Sunday
      #

      "$(cfbin)/noseyparker /iu/nexus/u1 $(sysadm) "
      "$(cfbin)/noseyparker /iu/nexus/u2 $(sysadm) " 
      "$(cfbin)/noseyparker /iu/nexus/u3 $(sysadm) " 
      "$(cfbin)/noseyparker /iu/nexus/u4 $(sysadm) " 
      "$(cfbin)/noseyparker /iu/nexus/u5 $(sysadm) " 
      "$(cfbin)/noseyparker /iu/nexus/u6 $(sysadm) " 
      "$(cfbin)/noseyparker /iu/nexus/ua $(sysadm) nomail" 
      "$(cfbin)/noseyparker /iu/nexus/ud $(sysadm) nomail" 

   nexus.longjob.Hr00::

      #
      # Update the GNU find/locate database each night
      #
 
      "$(gnu)/lib/locate/updatedb"
      "/local/iu/bin/newhomepage.sh"

###############################################################

editfiles:

    #
    # cfengine installs itself as a cron job - sneaky! :)
    #

    @{ /var/spool/cron/crontabs/root

    AppendIfNoSuchLine "0 * * * * $(cfbin)/cfwrap $(cfbin)/cfhourly"
    @}

   FTPserver::

      @{ /etc/shells

      AppendIfNoSuchLine "/bin/tcsh"
      AppendIfNoSuchLine "/local/gnu/bin/bash"
      @}


   XBootServer::

      @{ /etc/inetd.conf

      AppendIfNoSuchLine 
          "bootp dgram udp wait root /local/bin/bootpd bootpd -i -d"
      @}

   nexus::

      @{ /iu/nexus/ua/robot/.rhosts

      AppendIfNoSuchLine "borg"
      AppendIfNoSuchLine "borg.iu.hioslo.no"
      AppendIfNoSuchLine "aud4"
      AppendIfNoSuchLine "aud4.iu.hioslo.no"
      @}

   dax::

      @{ /etc/system

      AppendIfNoSuchLine "set pt_cnt=128"
      @}


######################################################################

required:

   #
   # Any host must have a /local, /usr/local fs. Check that
   # it exists and looks sensible. (i.e. not empty)
   #

   /$(site)/$(binserver)/local


######################################################################

copy:

   #
   # NIS seems broken at IU, so here we use NFS to fudge
   # a file distribution as a temporary solution. Actually
   # this makes the system work faster without NIS!
   #

      $(nisfiles)/services dest=/etc/services o=root g=other mode=0644
      $(nisfiles)/hosts.deny dest=/etc/hosts.deny o=root mode=0644

   !debian::

      $(nisfiles)/hosts    dest=/etc/hosts o=root g=other mode=0644

   PasswdServer::

      /etc/passwd dest=$(nisfiles)/passwd o=root g=other mode=0644
      /etc/shadow dest=$(nisfiles)/shadow o=root g=other mode=0644

   nexus::

      /local/iu/etc/dfstab dest=/etc/dfs/dfstab  o=root  mode=0744

   solaris.!PasswdServer::

      $(nisfiles)/passwd dest=/etc/passwd o=root g=other mode=0644
      $(nisfiles)/shadow dest=/etc/shadow o=root g=other mode=0600
      $(nisfiles)/group.solaris dest=/etc/group o=root g=other mode=0644

   linux::

      $(nisfiles)/passwd.linux dest=/etc/passwd o=root g=other mode=0644
      $(nisfiles)/group.linux dest=/etc/group o=root g=other mode=0644

###############################################################

processes:

      "eggdrop"                           signal=kill
      "irc"                               signal=kill
      "ping"                              signal=kill
      "NetXRay"                           signal=kill
      "netxray"                           signal=kill
      "ypserv"                            signal=kill
      "ypbind"                            signal=kill
      "rarpd"                             signal=kill
      "rpc.boot"                          signal=kill
      "README"                            signal=kill # You don't sh README !

   !XBootServer::

      "bootp"                             signal=kill

   #
   # These processes are not killed every hour, but once a day
   # when cfengine runs at night. Note that there are often
   # hanging pine and elm processes. These programs crash and
   # go berserk, using hundreds of hours of CPU time.
   #

   Hr00::

      "cron"                 signal=hup  # HUP these to update their config
      "inetd"                signal=hup

      "/local/sdt/sdt/bin"   signal=term # For those elektro dudes who forget
                                         # to log out
      "netscape"             signal=kill
      "pine"                 signal=kill
      "elm"                  signal=kill


###
#
# END cf.site
#
###

@end smallexample

@c .....................................................
@c SECTION
@c .....................................................

@node cf.motd, cf.users, cf.site, Example configuration file
@section cf.motd
@cindex @file{cf.motd}

@w{}
@smallexample

##################################################################
#
# cf.motd
#
# This file is used to set the message of the day file on
# each host
#
##################################################################
 
 #####
 #
 # BEGIN cf.motd
 #
 #####


control:

   #
   # This points to the file containing general text
   #

   masterfile      = ( /iu/nexus/local/iu/etc/motd-master )
   local_message   = ( /etc/motd.local )

editfiles:

      @{ /etc/motd

      BeginGroupIfFileIsNewer "$(masterfile)"
        EmptyEntireFilePlease
        InsertFile "$(masterfile)"
        InsertFile "$(local_message)"
        PrependIfNoSuchLine "This system is running $(class):$(arch)"
      EndGroup
      @}

 #####
 #
 # BEGIN cf.motd
 #
 #####

@end smallexample


@c .....................................................
@c SECTION
@c .....................................................

@node cf.users, cf.solaris, cf.motd, Example configuration file
@section cf.users

Whether or not you perform any special services for users, with or
without their consent is entirely a matter of local policy. In a school
or college situation, users are often uncooperative and some are even
irresponsible.  This file shows you what you could do in an environment
with inexperienced users, but please don't feel as though you have to be
this totalitarian.

@w{}
@smallexample
#################################################################
#
# cf.users - for iu.hioslo.no
#
# This file contains user specific actions
#
#################################################################

###
#
# BEGIN cf.users
#
###

ignore:

    robot

tidy:

   longjob::

     #
     # Some users just don't understand what they are doing
     # and this is safest, allbeit totalitarian
     #

     home                 pat=.rhosts                      age=0

     #
     # Tidy up users' home dirs
     #

     home                 pat=core             r=inf       age=0
     home                 pat=a.out            r=inf       age=1
     home                 p=*%                 r=inf       age=2
     home                 p=*~                 r=inf       age=2
     home                 p=#*                 r=inf       age=1    
     home                 p=*.dvi              r=inf       age=14   type=ctime
     home                 p=*.log              r=inf       age=2
     home                 p=Log.*              r=inf       age=3
     home                 p=CKP                r=inf       age=1
     home                 p=BAK                r=inf       age=1
     home                 p=log                r=inf       age=0
     home                 p=*.o                r=inf       age=0
     home                 p=*.aux              r=inf       age=3
     home                 p=*.zip              r=inf       age=7
     home/.deleted        p=*                  r=inf       age=0
     home/.wastebacket    p=*                  r=inf       age=14
     home/www             p=*~                 r=inf       age=1

     #
     # Clear the big cache files netscape creates
     #

     home/.netscape-cache  p=cache????*         r=inf       age=0
     home/.MCOM-cache      p=cache????*         r=inf       age=0
     home/.netscape/cache  p=*                  r=inf       age=0


#################################################################

files:

   AllHomeServers.longjob.rest::

     #
     # Check users files are not writable to the world
     # and there are no stale links (pointing nowhere)
     #

     home mode=o-w recurse=inf action=fixall # links=tidy

     home/.xsession mode=755 action=fixall
     home/.cshrc    mode=755 action=fixall

#################################################################

copy:

   Hr00.longjob::

   #
   # Make sure each user has an up to date standard
   # setup.  Cshrc just sources in a big standard file
   # which is kept in ~user/../.setupfiles/cshrc
   # to reduce disk wastage
   #

   $(masterfiles)/lib/Cshrc   dest=home/.cshrc
   $(masterfiles)/lib/tkgrc   dest=home/.tkgrc
   $(masterfiles)/lib/fvwm2rc dest=home/.fvwm2rc


###
#
# END cf.users
#
###
@end smallexample


@c .....................................................
@c SECTION
@c .....................................................


@node cf.solaris, cf.linux, cf.users, Example configuration file
@section cf.solaris

@w{}
@smallexample
#################################################################
#
# cf.solaris - for iu.hioslo.no
#
# This file contains Solaris specific patches
#
#################################################################

###
#
# BEGIN cf.solaris
#
###

directories:

     #
     # httpd/netscape want this to exist for some bizarre reason
     #

      /usr/lib/X11/nls

################################################################

tidy:

     /var/log  pattern=syslog.* age=0

   MailHub::

     /var/mail pattern=lp       age=0

#################################################################

files:

  #
  # If this doesn't exist fork will not work and the
  # system will not even be able to run the /etc/rc
  # scripts at boottime
  #

  /etc/system     o=root g=root m=644 action=touch

  /var/log/syslog o=root        m=666 action=touch

#############################################################

copy:

   #
   # Some standard setup files, can't link because
   # machine won't boot if their not on / partition.
   #

   /local/bin/tcsh dest=/bin/tcsh mode=755

   /local/iu/etc/nsswitch.standalone dest=/etc/nsswitch.conf

  #
  # Our named server uses a newer BIND
  # Put this here so that it will be preserved under
  # Solaris reinstallation
  #

  NameServers::

   /local/iu/sbin/in.named         dest=/usr/sbin/in.named         mode=555
   /local/iu/sbin/in.named.reload  dest=/usr/sbin/in.named.reload  mode=555
   /local/iu/sbin/in.named.restart dest=/usr/sbin/in.named.restart mode=555
   /local/iu/sbin/in.ndc           dest=/usr/sbin/in.ndc           mode=555
   /local/iu/sbin/named-xfer       dest=/usr/sbin/named-xfer       mode=555
   /local/iu/lib/nslookup.help     dest=/usr/lib/nslookup.help     mode=444

  any::
   /local/iu/lib/libresolv.a        dest=/usr/lib/libresolv.a      mode=444
   /local/iu/lib/libresolv.so.2     dest=/usr/lib/libresolv.so.2   mode=444
   /local/bin/nslookup              dest=/usr/sbin/nslookup        mode=444

##############################################################

editfiles:

      @{ /etc/netmasks

      AppendIfNoSuchLine "128.39  255.255.255.0"
      @}

      @{ /etc/defaultrouter

      AppendIfNoSuchLine "128.39.89.1"
      @}

      @{ /usr/openwin/lib/app-defaults/XConsole

      AppendIfNoSuchLine "XConsole.autoRaise: on"
      @}

   #
   # CERT security patch for vold vulnerability
   #

   @{ /etc/rmmount.conf

   HashCommentLinesContaining "action cdrom"
   HashCommentLinesContaining "action floppy"
   @}

##############################################################

disable:

    /etc/.login  type=file
    /etc/aliases 

   #
   # These files are ENORMOUS, don't let them fill the disk
   #

   Wednesday::

      /var/lp/logs/lpsched rotate=empty

      /var/adm/wtmpx       rotate=empty
      /var/adm/wtmp        rotate=empty

##############################################################

files:

    /etc/passwd        m=0644 o=root g=other action=fixplain
    /etc/shadow        m=0600 o=root g=other action=fixplain
    /etc/defaultrouter m=0644 o=root g=other action=touch
    /var/adm/wtmpx     m=0664 o=adm  g=adm   action=touch
    /var/adm/wtmp      m=0644 o=root g=adm   action=touch
    /var/adm/utmp      m=0644 o=root g=adm   action=fixplain
    /var/adm/utmpx     m=0664 o=adm  g=adm   action=fixplain

    /tmp m=1777                              action=fixdirs

##############################################################

disable:

   #
   # CERT security patch
   #

   /usr/openwin/bin/kcms_calibrate
   /usr/openwin/bin/kcms_configure
   /usr/bin/admintool

################################################################

shellcommands:

   AllBinaryServers.Saturday.longjob.Hr00::

      #
      # Make sure the man -k / apropos data are up to date
      #

      "/usr/bin/catman  -M /local/man"
      "/usr/bin/catman  -M /local/X11R5/man"
      "/usr/bin/catman  -M /usr/man"
      "/usr/bin/catman  -M /local/gnu/man"
      "/usr/bin/catman  -M /usr/openwin/share/man"
      "/usr/bin/catman  -M /local/X11R5/man"
      "/usr/bin/catman  -M /usr/share/man"

################################################################

editfiles:


      #
      # A painless way to add an rc.local script to the rc files
      # under Solaris without having to fight though inittab
      #

      @{ /etc/rc3.d/S15nfs.server

      AppendIfNoSuchLine "sh /local/iu/etc/rc.local"
      @}

      #
      # umask defined when inetd starts is inherited by all subprocesses
      # including ftpd which saves with mode 666 (!) unless we do this
      #

      @{ /etc/rc2.d/S72inetsvc

      PrependIfNoSuchLine "umask 022"
      @}


###
#
# END cf.solaris
#
###

@end smallexample


@c .....................................................
@c SECTION
@c .....................................................

@node cf.linux, cf.freebsd, cf.solaris, Example configuration file
@section cf.linux

@w{}
@smallexample
#################################################################
#
# cf.linux - for iu.hioslo.no
#
# This file contains debian linux specific patches
#
#################################################################

###
#
# BEGIN cf.linux
#
###

files:

      /etc/printcap m=644 o=root action=fixplain

     #
     # Cert advisories
     #

      /bin/mount         m=755 o=root action=fixall
      /bin/umount        m=755 o=root action=fixall

#######################################################################

  disable:

     #
     # Cert advisories
     #

      /sbin/dip-3.3.7n

########################################################################

links:

    /local/bin/tcsh   ->  /bin/tcsh

    /local/lib/mail   ->  /$(site)/$(main_server)/local/lib/mail

########################################################################

editfiles:

  #
  # Samba default mode needs to be set...
  #

   @{ /etc/smb.conf

   ReplaceAll "700" With "644"
   @}

  #
  # Linux date is very stupid and needs a very careful
  # TZ definition, otherwise it loses
  #

   @{ /etc/csh.cshrc

   AppendIfNoSuchLine "setenv TZ 'MET-1MET DST-2,M3.5.0/2,M10.5.0/3'"
   @}

  #
  # resolv+ ordering
  #

   @{ /etc/host.conf

   PrependIfNoSuchLine "order bind"
   @}


  #
  # Should have been configured already (!)
  #

   @{ /etc/ld.so.conf

   AppendIfNoSuchLine "/usr/X11R6/lib"
   @}

  #
  # Kill annoying messages
  #

   @{ /etc/cron.daily/standard

   HashCommentLinesContaining "security"
   @}

#########################################################################

shellcommands:

  Hr00::

     #
     # Find/locate database
     #

     "/usr/bin/updatedb"

###
#
# END cf.linux
#
###


@end smallexample


@c .....................................................
@c SECTION
@c .....................................................

@node cf.freebsd, cfservd.conf, cf.linux, Example configuration file
@section cf.freebsd / cf.netbsd

FreeBSD, OpenBSD and NetBSD are sufficiently similar to have a single
file for all.

@smallexample
#################################################################
#
# cf.bsd - for iu.hioslo.no
#
# This file contains bsd specific patches
#
#################################################################

###
#
# BEGIN cf.bsd
#
###

links:

    /usr/spool        ->  /var/spool
    /local/bin/tcsh   ->  /bin/tcsh
    /local/bin/perl   ->  /usr/bin/perl
    /usr/lib/sendmail ->  /usr/sbin/sendmail

#################################################################

files:

   /usr/tmp mode=1777 owner=root action=fixall

#################################################################

editfiles:

   #
   # Comment out all lines to shut up this annoying cfengine-like
   # script, which sends mail every day!!!
   #

   @{ /etc/crontab

   HashCommentLinesContaining "daily"
   HashCommentLinesContaining "weekly"
   HashCommentLinesContaining "monthly"
   @}

#################################################################

copy:

      $(masterfiles)/etc/printcap.client      dest=/etc/printcap mode=0644

#########################################################################

shellcommands:

  Hr00::

    "/usr/libexec/locate.updatedb"
    "/usr/bin/makewhatis /usr/share/man:/usr/X11R6/man"

###
#
# END cf.bsd
#
###


@end smallexample

@c .....................................................
@c SECTION
@c .....................................................

@node cfservd.conf,  , cf.freebsd, Example configuration file
@section cfservd.conf tutorial
@cindex @file{cf.site}

@w{}
@smallexample
#########################################################
#
# This is a cfservd config file
#
#########################################################

 #
 # Could import cf.groups here and use a structure like
 # in cfengine.conf, cf.main, cf.groups
 #

control:

  public = ( /usr/local/publicfiles )

  almost_public = ( /usr/local/almostpublicfiles )

  cfrunCommand = ( /iu/nexus/ud/mark/comp/Tests/cfrun-command )

  MaxConnections = ( 10 )

#########################################################

admit:   # or grant:

     $(public) *

     $(almost_public) *.iu.hioslo.no *.gnu.ai.mit.edu

     /etc/passwd *.iu.hioslo.no

     #
     # Who can exec cfengine remotely?
     #

     $(cfrunCommand) *.iu.hioslo.no

#########################################################

deny:

     $(public)/special *.moneyworld.com


@end smallexample



@c **********************************************************************
@c INDEX
@c **********************************************************************

@node Variable Index, Concept Index, Example configuration file, Top
@unnumbered Variable Index

@printindex vr

@node Concept Index, FAQ Index, Variable Index, Top
@unnumbered Concept Index

@printindex cp

@node FAQ Index,  , Concept Index, Top
@unnumbered FAQ Index

@printindex mb

@ifhtml
@html
<a name="Contents">
@end html
@end ifhtml

@contents

@ifhtml
@html
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2576171-2");
pageTracker._initData();
pageTracker._trackPageview();
</script>
@end html
@end ifhtml

@bye

