This is cfengine-Reference.info, produced by makeinfo version 4.2 from
cfengine-Reference.texinfo.

INFO-DIR-SECTION System Utilities
START-INFO-DIR-ENTRY
* 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-INFO-DIR-ENTRY


File: cfengine-Reference.info,  Node: Owner and group wildcards,  Next: Files linkchildren,  Prev: home directive,  Up: files

Owner and group wildcards
-------------------------

   If you do not want to explicitly state the owner or group of a file
you may simply omit the group or owner options.


       /FILE-OBJECT m=0664 r=inf
   This example generate a warning if any files under the named
directory do not have permission read/write for all users.


File: cfengine-Reference.info,  Node: Files linkchildren,  Next: touch,  Prev: Owner and group wildcards,  Up: files

Files linkchildren
------------------

   The `linkchildren' facility is almost identical to that already
described under `links'.  *Note Link Children::.  The only difference
here is that the ownership and permissions on the links are set all in
one operation.  For example:

     MYCLASS::
     
        /local/lib/emacs m=0770 o=me g=mygroup act=linkchildren


File: cfengine-Reference.info,  Node: touch,  Next: create,  Prev: Files linkchildren,  Up: files

touch
-----

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

     MYCLASS::
     
        /NEWFILE mode=0644 action=touch


File: cfengine-Reference.info,  Node: create,  Prev: touch,  Up: files

create
------

   This is like `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 `0644'.


File: cfengine-Reference.info,  Node: filters,  Next: groups,  Prev: files,  Up: Cfagent reference

filters
=======

   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 `copy', `editfiles', `files', `tidy'
and `processes'. In most cases one writes

     .. filter=<i>filteralias</i>
   in the appropriate command. The exception is `editfiles', where the
syntax is

     {
     ..
     Filter "filteralias"
     ..
     }
   Example:


     files:
     
      /tmp filter=testfilteralias action=alert r=inf

   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:

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

   Filters are evaluated like classes. In fact, the filtering works by
evaluating the class attributes for each file.

   File filters:

`Owner:'
     and Group can use numerical id's or names, or ```none''' for users
     or groups which are undefined in the system passwd/group file.

`'
     Mode: applies only to file objects. It shares syntax with the
     `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.

`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

          (year,month,day,hour,minutes,seconds)
     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.

            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

`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

          file|reg|link|dir|socket|fifo|door|char|block
     Note that `file' and `reg' are synonymous.

`ExecRegex:'
     matches the test string against the output of the specified
     command.

`NameRegex:'
     matches the name of the file with a regular expression.

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

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

`Result:'
     specifies the way in which the above elements are combined into a
     single filter.

   Process filters:

`Owner'
     process owner UID (quoted regex)

`PID:'
     process ID (quoted regex)

`PPID:'
     parent process ID (quoted regex)

`PGID:'
     process group ID (quoted regex)

`RSize:'
     resident size (quoted regex)

`VSize:'
     virtual memory size (quoted regex)

`Status:'
     status (quoted regex)

`Command:'
     CMD or COMMAND fields (quoted regex)

`(From/To)TTime:'
     Total elasped time in TIME field (accumulated time)

`(From/To)STime:'
     Starting time for process in STIME or START field (accumulated
     time)

`TTY:'
     terminal type, or none (quoted regex)

`Priority:'
     PRI or NI field (quoted regex)

`Threads:'
     NLWP field for SVR4 (quoted regex)

`Result:'
     logical combination of above returned by filter (quoted regex)
Examples: processes started between 18th Nov 2000 and now.

       { filteralias
     
       FromSTime: "date(2000,11,18,0,0,0)"
       ToSTime:   "now"
       }
   All processes which have accumulated between 1 and 20 hours of CPU
time.

       { filteralias
     
       FromTTime:  "accumulated(0,0,0,1,0,0)"
       ToTTime:    "accumulated(0,0,0,20,0,0)"
       }

* Menu:

* Complete filter examples::


File: cfengine-Reference.info,  Node: Complete filter examples,  Prev: filters,  Up: filters

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.


     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
       }
   Find all ELF executables using data from the Unix `file' command.
Caution, this takes a long time if used indescriminately.


     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"
       }
   Here is an example which warns of any process coupled to a terminal
started in November:

     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


File: cfengine-Reference.info,  Node: groups,  Next: homeservers,  Prev: filters,  Up: Cfagent reference

groups/classes
==============

   The `groups' action (equivalently referred to as `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 _netgroups_ then this idea will already be familiar to you and
you can probably use your already-defined netgroups in cfengine.

   To define a group, you simply make a list and assign it a name.
Here is an example of the syntax:


     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

To include a list of hosts from a NIS netgroup, you use the `+' symbol,
or the `+@' construction.  For example:


     groups:
     
        science = ( +science-allhosts )
     
        physics = ( +physics-allhosts )
     
        physics_theory = ( +@physics-theory-sun4 dirac feynman schwinger )

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.  `$(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 _except_
for certain hosts.  You can `undefine' or remove hosts from the netgroup
list by using the minus `-' symbol.  For example:


     group = ( +mynetgroup -specialhost -otherhost )

which means, of course, all hosts in netgroup `mynetgroup' except for
`specialhost' and `otherhost'.  Finally, you may also subtract two
netgroups in the following manner.

     group = ( +bignetgroup -smallnetgroup )

The `minus' command effectively eliminates its members from
`bignetgroup' if they exist within that group.  If none of the hosts in
`smallnetgroup' exist in `bignetgroup' then the command has no effect.

   Groups may contain previously defined cfengine groups too. This
allows one class to inherit the attributes of another class, for
instance:


       AllSun4Hosts   = ( sonny sunny solar stella )
       AllUltrixHosts = ( ully olly wally golly )
     
       AllBSD = ( AllSun4Hosts AllUltrixHosts )

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.


       SpecialTimes = ( Hr00 Monday Day1 )

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:


      Hr00::
     
       SpecialTime = ( Monday Tuesday )
   defines `SpecialTime' at Hr00 on Monday or Tuesday.

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


        have_cc = ( '/bin/test -f /usr/ucb/cc' )

The class `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.


File: cfengine-Reference.info,  Node: homeservers,  Next: ignore,  Prev: groups,  Up: Cfagent reference

homeservers
===========

   The `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:


     homeservers:
     
        Physics::  einstein
        Math::     riemann euler

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
`homepattern' is used to determine which resources are home directories
in the list of `mountables'.  *Note mountables::.

   Let us consider an example in which `homepattern' is set to the
wildcard value `home?' and the mountables list is given by

     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

   Any host in the group `Physics' would now want to mount all home
directories from the host `einstein'.  There are two of these.  Both
the filesystems listed for `einstein' match the `homepattern' variable
since they end in `home?'.  cfengine would therefore take this to mean
that all hosts in `Physics' should mount both of these filesystems.

   Hosts in `Math', on the other hand, should mount only
homedirectories from the hosts `riemann' and `euler'.  There is only a
single filesystem on `riemann' and it does not match `homepattern', so
it is not mounted.  On `euler' there is a match, so this filesystem
will be added to the appropriate hosts.

   _Cfengine picks out home directory resources from the `mountables'
list by trying to match the `homepattern' variable, starting from the
end of the directory name.  You do not therefore have to use the
designation `/site/host/home?'  but this is a simple choice and is
highly recommended._


File: cfengine-Reference.info,  Node: ignore,  Next: import,  Prev: homeservers,  Up: Cfagent reference

ignore
======

   When you specify a recursive search as part of a `files', `tidy' or
`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


       ignore:
     
          WILDCARDS/DIRECTORIES/FILENAMES

   For example:


     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

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.

   A handy tip if you are tidying `/tmp' recursively is to include the
directory `.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.


File: cfengine-Reference.info,  Node: import,  Next: interfaces,  Prev: ignore,  Up: Cfagent reference

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:


     import:
     
        any::
     
           cf.global_classes
     
     
        linux::
     
           cf.linux_classes

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


File: cfengine-Reference.info,  Node: interfaces,  Next: links,  Prev: import,  Up: Cfagent reference

interfaces
==========


      interfaces:
     
        CLASSES::
     
          INTERFACENAME netmask=NETMASK broadcast=BROADCAST

   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 `control:'. If the
`netmask' variable is not set, cfengine ignores the default interface
configuration.  Example:


       interfaces:
     
         "le1" netmask=255.255.255.0 broadcast=ones
         "le2" netmask=255.255.255.0 broadcast=ones


File: cfengine-Reference.info,  Node: links,  Next: mailserver,  Prev: interfaces,  Up: Cfagent reference

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 `linkchildren' feature is also available from
the `files' action  *Note files::. The syntax of a link item is:


       FROM-LINK ->[!] TO-OBJECT
      OR
       FROM-LINK +>[!] TO-OBJECT
     
                 type=symbolic/absolute/abs/HARD/RELATIVE/REL
                 copy=PATTERN
                 recurse=NUMBER/INF/0
                 copytype=CHECKSUM/ctime
                 include=PATTERN
                 exclude=PATTERN
                 ignore=PATTERN
                 action=SILENT
                 deadlinks=kill/FORCE
                 define=CLASSLIST
                 nofile=kill/FORCE
                 syslog=TRUE/ON/FALSE/OFF
                 inform=TRUE/ON/FALSE/OFF
                 ifelapsed=MINS
                 expireafter=MINS

_The special variable `$(binserver)' can be used in `links'._

* Menu:

* Single links::
* Multiple Links::
* Link Children::
* Relative and absolute links::
* Hard links::


File: cfengine-Reference.info,  Node: Single links,  Next: Multiple Links,  Prev: links,  Up: links

Single links
------------

   To define a single link, you create an entry of the following form:


     links:
     
       CLASS::
     
          LINKNAME -> OBJECT_TO_LINK_TO
          LINKNAME -> ./RELATIVE_LINK
          LINKNAME -> ../RELATIVE_LINK

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 `!' 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 `-L'
is used, in which case the link is deleted.

   Here is an example of some valid link statements.


     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

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 `.cfsaved'
to the filename, or by moving to a repository, whereas old links are
removed.  The same effect can be enforced globally using the `-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

`type=HARD/RELATIVE/ABSOLUTE'
     If the link type is hard, a hard link is created *Note Hard
     links::.  Symbolic links may specify two special types. If
     `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 `.' and `..' to move relative to the
     current directory. For instance, a link from `/usr/local/file' to
     `/usr/file' would be linked as `./../file'.  If the `to' object is
     already relative, this has no effect.

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

`copy=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 *Note copylinks::.
     Directories cannot be copied in this way.

`copytype=CHECKSUM/CTIME'
     This specifies the basis for deciding whether to update a file
     which is to be copied instead of linked *Note copy::.

`nofile=kill/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 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.

`exclude=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
     *Note excludelinks::.

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

`recurse=NUMBER/inf'
     This option can only be used with multiple link operations *Note
     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. `inf' means infinite
     recursion. Cfengine also ignores files and directories in the
     ignore list *Note ignore::.

`define=CLASSLIST'
     If a link is created or replaced, the colon, comma or dot separated
     list of classes becomes defined.

   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 `$(binserver)'.  The easiest way to understand
this feature is to illustrate a couple of examples.  Consider the
following:

     links:
     
        any::
     
           /local -> /${site}/${binserver}/local

The result of this command is quite different depending on which host is
executing it.  The variable `$(site)' clearly has a fixed value, but
the variable `$(binserver)' might expand to any valid binary server for
the host executing the program.  *Note 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 `$(binserver)' with each of its valid binservers in turn
and it matches the first one binary server which yields an existing
file.

   Note that every host is a binary server for itself, so that the
value of `$(binserver)' which has absolute priority is alway the same
as the value of `$(host)'.  This ensures that the link will always be
made to a local filesystem if the rules of the model are upheld.


File: cfengine-Reference.info,  Node: Multiple Links,  Next: Link Children,  Prev: Single links,  Up: links

Multiple Links
--------------

   With the link symbol `+>', 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


     links:
     
       myclass::
     
          /usr/local/bin +>  /usr/local/lib/perl/bin
          /opt           +>! /local

every file in the directory `/usr/local/lib/perl/bin' is linked
symbolically to a corresponding file in `/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 `.cfsaved' to the filename *Note repository::.

   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 `-L' command
line option is used, in which case the link is deleted.


File: cfengine-Reference.info,  Node: Link Children,  Next: Relative and absolute links,  Prev: Multiple Links,  Up: links

Link Children
-------------

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

   Consider the following:

     links:
     
        any::
     
           /usr/local/lib/emacs +> linkchildren

The word `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 `lib' and look for a filesystem ending in `lib'.  If
this is not found we go to `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 `host:/site/host/local'.  It would then try to locate
`host:/site/host/local/lib/emacs' and link all of the children therein
to the local file directory `/usr/local/lib/emacs'.

   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 `/usr/local' from the binary architecture
server, but you also want to use the disk you have locally.  The
following lines

     links:
     
        electron::
     
           /$(site)/electron/local +> linkchildren
     
        any::
     
           /usr/local              -> /$(site)/$(binserver)/local

have the effect of creating a directory `/$(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 `/usr/local' to
the `nearest' binary server.  But the nearest binary server is always
`$(host)' which means this evaluates to a file which now exists because
of the first command, so on the host `electron' the directory
`/usr/local' ends up being a link to `/$(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 *Note files::.  Nevertheless, this feature clearly
requires some caution and is mainly a spice for advanced users of the
cfengine model.


File: cfengine-Reference.info,  Node: Relative and absolute links,  Next: Hard links,  Prev: Link Children,  Up: links

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:


        /var/tmp/cfengine -> /local/cfengine

If we add the option `type=relative', then instead of creating a link
which points to `/local/cfengine', the link is created pointing to the
location

       ./../../local/cfengine

In other words, the link is relative to the calling directory
`/var/tmp'.

   If a link is specified as being absolute with the option
`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 `/local' is really a link to
`/site/myhost/local' then the link would point to
`/site/myhost/local/cfengine'.


File: cfengine-Reference.info,  Node: Hard links,  Prev: Relative and absolute links,  Up: links

Hard Links
----------

   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 `type=hard'. For example:


     links:
     
        /DIRECTORY/NEWNAME -> /DIRECTORY/OTHERNAME type=hard

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.


File: cfengine-Reference.info,  Node: mailserver,  Next: methods,  Prev: links,  Up: Cfagent reference

mailserver
==========

   The `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:


     mailserver:
     
        CLASS::      mailhost:/var/spool/mail

The result of the `mailcheck' command in the action-sequence is now to
mount the filesystem `/var/spool/mail' on the host `mailhost'.  This
action is carried out on any machine which does not already have that
filesystem mounted.

   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
`/usr/mail' by default, whereas on a Sun system it would be mounted on
`/var/spool/mail'.  The default location can be changed by using the
resource file.  *Note cfrc resource file::.


File: cfengine-Reference.info,  Node: methods,  Next: miscmounts,  Prev: mailserver,  Up: Cfagent reference

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.

   _Modules 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 is not recommended for large
production environments until this paragraph is removed from the
documentation.)

   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.


       methods:
     
          CLASS::
     
     
            FUNCTION_NAME(PARAMETERS OR NONE)
     
           action=`filename'
     
           sendclasses=COMMA SEPARATED CLASS LIST
     
           returnvars=COMMA SEPARATED VARIABLE LIST OR VOID
           returnclasses=COMMA SEPARATED CLASS LIST
     
           server=IP-HOST/*
     
           forcereplyto=IP ADDRESS
     
           owner=SETUID
           group=SETGID
           chdir=CD FOR CHILD
           chroot=SANDBOX DIRECTORY
Most of these functions will be familiar from other cfengine
commands. Some special ones are noted below:

`action'
     The name of the method file that should be defined in the modules
     directory of the server host.

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

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

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

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

   The function arguments may not be empty, but a null value can be
transmitted with a dummy value, e.g. `Function(null)' or
`function(void)'.  Here is an example method call.


      # cfagent.conf
     
     control:
     
        actionsequence = ( methods )
     
     #################################################
     
     methods:
     
      any::
     
        SimpleMethod(null)
     
           action=cf.simple
           returnvars=null
           returnclasses=null
           server=localhost
   With method file (located in the ModulesDirectory),


      # cf.simple
     
       control:
     
         MethodName       = ( SimpleMethod )
         MethodParameters = ( null )
         actionsequence   = ( timezone )
     
     
       classes:
     
          dummy = ( any )
     
     ####################################################
     
     alerts:
     
      dummy::
     
       "This simple method does nothing"
     
       ReturnVariables(void)
       ReturnClasses(void)
   On executing this example, the output is:
     nexus$ ./cfagent -f ./cftest
     cfengine:myhost:SimpleMethod: cfengine:nexus: This simple method does nothing

   If the server name is a wildcard, e.g. `*' then this acts as a
multicast or broadcast.

* Menu:

* localhost examples::
* remotehost examples::


File: cfengine-Reference.info,  Node: localhost examples,  Next: remotehost examples,  Prev: methods,  Up: methods

Localhost examples
------------------

   The following example collects the tar file, unpacks it, configures
and compiles it, then tidies its files.

     ####################################################
     #
     # 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
   We must install the method in the trusted modules directory
(normally /var/cfengine/modules or WORKDIR/modules).

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

   A more complex example is given below:

       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
   Here the function being called is the cfengine program
`cf.methodtest'.  It is passed three arguments: the contents of
variable PARENT1, the literal string "param2" and the first 300 bytes
of the file `/etc/passwd'.  On return, if the method gets executed, the
values will be placed in the four variables:

     $(GetAnalysis.a) $(GetAnalysis.b) $(GetAnalysis.c) $(GetAnalysis.d)
   If the classes `define1' etc, are returned by the method, then we
set them also in the main program as
     GetAnalysis_define::
   In other words, the class name is also prefixed with the method name
to distinguish it.  (`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 `server=' declaration.
The server side should have no `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:

   control:

   MethodName       = ( IDENTIFIER )     MethodParameters = ( SPACED
LIST OF RECIPIENT VARIABLES OR FILES )

   # ....

   alerts:

   # Return variables are alerts to parent

   ReturnVariables(COMMA SEPARATED LIST OF VARIABLES OR FUNCTIONS OR
VOID)     ReturnClasses(COMMA SEPARATED LIST OF CLASSES)

   e.g.

     control:
     
      MethodName       = ( GetAnalysis )
      MethodParameters = ( value1 value2 /tmp/file1 )
     
      # ....
     
     alerts:
     
       # Return variables are alerts to parent
     
       ReturnVariables("${var1}","${var2}","var3",literal_value)
       ReturnClasses(class1,class2)

   The parameters transmitted by the parent are read into the formal
parameters `value1', `value2' and the the file excerpt is placed in the
temporary 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.


File: cfengine-Reference.info,  Node: remotehost examples,  Prev: localhost examples,  Up: methods

Remote host examples
--------------------

   Methods can also be scheduled for execution on remote hosts.
   * Both hosts must have an identical copy of the method stanza

   * Public keys must be exchanged between the cooperating hosts

   * Access must be granted to `/var/cfengine/rpc_out' in cfservd.

   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 `update.conf'.

     control:
     
      MethodPeers = ( HOSTNAME LIST )
   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?  For example, to make two hosts collaborate:

     methods:
     
      host1|host2::
     
       MethodTest("my test!")
     
       action=cf.methodtest
       server=host2.iu.hio.no
       returnclasses=null
       returnvars=retval
       ifelapsed=120

   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.


File: cfengine-Reference.info,  Node: miscmounts,  Next: mountables,  Prev: methods,  Up: Cfagent reference

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:


     miscmounts:
     
        CLASS::
     
           INFOHOST:SOURCE-DIRECTORY DESTINATION MODE
     
           INFOHOST:SOURCE-DIRECTORY DESTINATION mode=MODE
     
          ifelapsed=MINS expireafter=MINS

For example


        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

This statement would mount the directory `/$(site)/libraryserver/data'
physically attached to host libraryserver onto a directory of the same
name on all hosts in the group `physics'.  The modes `ro' and `rw'
signify read-only and read-write respectively.  If no mode is given,
read-write is assumed.


File: cfengine-Reference.info,  Node: mountables,  Next: processes,  Prev: miscmounts,  Up: Cfagent reference

mountables
==========

   The `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 `binservers' and `homeservers' to
determine which filesystems a given host should mount, according to the
cfengine model.

   The syntax of the list is:

     mountables:
     
        CLASS::
            "filesystem to mount"
     	   readonly=false/off/TRUE/ON
     	   mountoptions=NFS-OPTIONS
   e.g.


     mountables:
     
        CLASS::
     
        server:/site/server/u1
        server:/site/server/local
        linuxhost:/site/linuxhost/local
        linuxhost:/site/linuxhost/u1

Notice that binary and home-directory filesystems are mixed freely here.
Cfengine determines which of the entries are homedirectories using the
`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.

   _NOTE: This list is read in order, top down.  Cfengine looks for the
first filesystem matching a given binary server when expanding the
variable `$(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
`AutomountDirectResources'.

