CFPEEK(1)

NAME
cfpeek - retrieve values from a structured configuration file

SYNOPSIS
cfpeek [OPTION]... FILE [PATH...]

DESCRIPTION
Structured configuration files keep program configuration values in a hierarchical structure. Examples of such files are mailutils.conf, used by GNU Mailutils, named.conf, used by named, or ~/.gitconfig, used by GIT.

Cfpeek provides a uniform and consistent command line interface for various operations on such files. It can be used to retrieve configuration values, both by literal keyword matches and by using wildcard patterns, to reformat the files in arbitrary way, and to apply an external script to each statement in the file.

This manpage is a short description of cfpeek. For a detailed discussion, including examples of the configuration and usage recommendation, refer to the Cfpeek User Manual available in Texinfo format. To access it, run:

  info cfpeek

Should any discrepancies occur between this manpage and the Cfpeek User Manual, the later shall be considered the authoritative source.

  Input formats
Cfpeek is able to handle input files in several formats:

GRECS
    The default input format. This format is used, e.g., by GNU Dico, GNU Mailutils, Mailfromd and others. The following is a short description. See grecs_config(5), for a detailed discussion of the format and its features.

    The GRECS input file consists of simple and block statements. Simple statements consist of a keyword and value, separated by any amount of whitespace. Simple statements are terminated with a semicolon, e.g.:

    wakeup 15;

    A value can be either a single scalar value, as in the example above, or several values, separated by whitespace, or a list of values: a comma-separated list, enclosed in a pair of braces, e.g.:

    path ("/usr","/usr/bin");

    Block statements are used for logical grouping of other statements. A block statement consists of a keyword, optionally followed by a value, and a set of other statements, enclosed in a pair of curly brackets, e.g.:

    syslog {
         facility local1;
         tag foo;
    }

    A semicolon may follow the closing }, although this is not required.

    The whitespace (i.e. space characters, tabs and newlines) has no special syntactical meaning, except that it serves to separate otherwise adjacent tokens.

    Several types of comments are supported. A single-line comment starts with a # or // and continues to the end of the line. A multi-line comment starts with the two characters /* (slash, star) and continues until the first occurrence of */ (star, slash). Whatever comment type are used, they are removed from the configuration prior to parsing it.

    After comment removal, the Grecs configuration is normally preprocessed using m4.

PATH
    A line-oriented “keyword path” format. It is similar to X-resource format, used by X window system configuration files. Each line consists of a keyword pathname, followed by a semicolon, a single space character and the value of that keyword.

    Comments (introduced with a # character) and empty lines are ignored.

    This format is used by default in cfpeek output.

BIND
    The format used by named DNS daemon. It is similar to GRECS, except that it requires the use of semicolon after block statements, does not support list values and here-document syntax, etc. See named.conf(5), for a detailed description.

DHCPD
    The format used by dhcpd daemon. It is similar to BIND, with a few exceptions. See dhcpd.conf(5), for a detailed description.

META1
    The format used by MeTA1 configuration file. Similar to GRECS, in some aspects. The most prominent differences are: the use of the equals sign between the keyword and its value and the use of curly brackets to enclose list values. Only one-line comments are allowed, the # serves as a comment starter. See http://www.meta1.org, for a detailed description.

GIT The format used by git configuration files. See the section CONFIGURATION FILE in git-config(1).

  Full dump
When used with a single non-optional argument, FILE, cfpeek parses that file and outputs its contents in a so called path-value form. Each line of this output consists of a full keyword pathname, followed by a semicolon, a single space and a value.

The full keyword pathname identifies that particular statement within the file. It is similar to UNIX file pathname, and consists of the names of all sections (block statements) within which the keyword appears. A dot is used as path component separator. For example, given the following (GRECS-style) configuration file:

foo {
  bar {
    baz 45;   # A.
  }
  baz 98;     # B.
}

The full pathname of the statement marked with A can be written as:

 .foo.bar.baz

Similarly, the statement marked with B has the following pathname:

 .foo.baz

A block statement that has a tag is referred to by its name, followed by an equals sign, followed by the tag value. For example, the statement A in the file below:

program x {
  bar {
    baz 45;   # A.
  }
}

is identified by the following pathname:

 .program=x.bar.baz

The tag can optionally be enclosed in a pair of double quotes. Such a quoting becomes mandatory for tags that contain white space or path component separator, e.g.:

 .program="a.out".bar.baz

See grecs_stmt_path(5), for a detailed description of this format.

  Keyword lookup
Any additional arguments, if specified, are treated as pathnames of the keywords to find in the file. For each additional argument (hereinafter referred to as search key), the corresponding keyword is looked up in the configuration and output in the path-value form. All possible matches are shown, unless limited by the --matches option (see below).

Any number of search keys can be given in the command line. If a search key produces no matches, a diagnostic message is issued unless the -q (--quiet) has been given, which suppresses this behavior.

By default, wildcard match is assumed. A % character in place of a keyword matches any single keyword. Thus:

cfpeek file.conf .%.bar.baz

will match .foo.bar.baz, .qux.bar.baz, but will not match .bar.baz or .x.y.bar.baz.

A single * character in place of a keyword matches zero or more keywords appearing in its place, so that

cfpeek file.conf .*.bar.baz

would match all pathnames listed above.

Block statement tags are matched using the traditional globbing patterns (see fnmatch(3) ), e.g.:

cfpeek file.conf .*.program="mh-*"

will match any program block statement whose tag begins with “mh-”.

The literal matching can be requested with the -L (--literal) option.

  Scripting
The scripting mode is enabled when at least one of -f (--file) or -e (--expression) options is given. This is a highly useful advanced feature, which allows you to apply programs of arbitrary complexity to each node of the parsing tree. For a detailed discussion, see the section SCRIPTING.

OPTIONS

  Output control

-H, --format=FLAGS
    Sets output format flags. FLAGS is a comma-separated list of one or more of the following:

    parent=NAME
        Search for a parent node with the given NAME and print it.
    child=NAME
        Locate a child of the current node which has the identifier NAME and print it.
    sibling=NAME
        Find in the current node the first sibling identified by NAME. See the example 7 in the EXAMPLES section below.
    up=N
        Print Nth parent node.
    down=N
        Print the node located N levels of hierarchy below the current one.
    delim=CHAR
        Use CHAR as path component delimiter, instead of the default dot.
    The flags below are boolean. When prefixed with no they have the meaning opposite to the described.
    [no]locus
        Print source location of each configuration statement. A location is printed as the file name, followed by a semicolon, followed by the line number and another semicolon. Locations are separated from the rest of output by a single space character.
    [no]path
        Print the statement path. See grecs_stmt_path(5), for a description. If printed, the path is separated from the rest of output on its right by a semicolon and a space.
    [no]value
        Print the statement value.
    [no]quote
        Always quote values. By default, the value will be quoted only when necessary, i.e. if it contains white space, quotes or special characters.
    [no]never-quote
        Never quote values.
    [no]quote-hex
        Print non-printable characters as C hex escapes. This option is ignored if noquote is set.
    [no]descend
        Descend into subnodes.
    [no]default
        Set default options. This is equivalent to:

        delim=.,path,value,quote

-q, --quiet
    Suppress error diagnostics.

  Modifiers

-L, --literal
    Use literal matching.

-S, --sort
    sort parse tree lexicographically

-m, --matches=NUMBER
    output at most NUMBER matches

-p, --parser=TYPE
    Select input parser type. Valid values for TYPE are:

    GRECS
        File format used by the Grecs library. This format is used, e.g., by GNU Dico, GNU Mailutils, Mailfromd and others. This is the default. See grecs_config(5), for a detailed description.
    META1
        Format used by MeTA1 configuration file. See http://www.meta1.org.
    BIND
        Format used by named. See named.conf(5) DHCPD Format used by dhcpd. See dhcpd.conf(5)
    GIT Format used by git configuration files. See the section CONFIGURATION FILE in git-config(1).
    PATH
        Keyword path format.

-r, --reduce
    Reduce the parse tree, so that each keyword occurs no more than once at each tree level.

-s, --set=PATH=VALUE
    Set a keyword PATH to VALUE. This will be reflected in the output,

  Scripting

-e, --expression=EXPRESSION
    Apply this Scheme expression to each node found.

-f, --file=FILE
    Apply the Scheme script FILE to each node found. The script must define the function (cfpeek node). See the section SCRIPTING, for a detailed description. If both --file and --expression are given, the file is loaded first, and expression is applied to each node.

-i, --init=EXPR
    This option provides an initialization expression, which is evaluated once, after loading the script file, if one is specified, and before starting the main loop.

-d, --done=EXPR
    This option supplies a cleanup expression. The expression will be evaluated once, after the main loop finishes.

-l, --lang=NAME
    Select scripting language to use. This is reserved for future use.

  Preprocessor control
GRECS input files are preprocessed by default using m4 -s. BIND input files are preprocessed only if the --preprocessor option (see below) is given, which specifies the preprocessor binary to use.

Files in another input formats are never preprocessed.

The options below control the preprocessor invocation for those formats that support it.

-D, --define=SYMBOL[=VALUE]
    Define a preprocessor symbol.

-I, --include-directory=DIR
    Add DIR to the list of files searched for include files.

-N, --no-preprocessor
    Disable preprocessing.

-P, --preprocessor=COMMAND
    Use COMMAND as a preprocessor, instead of the default m4.

  Debugging

-X, --debug-lexer
    Debug configuration file lexer.

-x, --debug-parser
    Debug configuration file parser.

  Other options

-V, --version
    Print program version.

-h, --help
    Print a short option summary.

--usage
    Print a short usage message and a list of available options.

SCRIPTING
Cfpeek enters the scripting mode when at least one of the -f (--file) or -e (--expression) options is given.

So far only Scheme is supported as a scripting language.

The file supplied with the -f (--file) option must be a valid Scheme source and it must define the function cfpeek as shown in the following example:

(define (cfpeek node)
 ...)

This function will be called for each statement found. The statement itself will be passed to it as node argument. A node is an opaque data type describing a single node in the parse tree. Each node corresponds to a single statement in the configuration file (be it simple or block statement). It holds all the information necessary to identify this statement: its type (simple or block), location in the source file, identifier (or keyword), value and, if it describes a block statement, pointers to the nodes below it. Nodes form doubly-linked lists both horizontally (i.e. statements on the same nesting level) and vertically (i.e. links between parent block statements and their substatements and vice-versa), so that every node in the tree can be reached from arbitrary another node, and can thus be used as a starting point to traverse the entire tree.

A number of functions is provided to access the information stored in a node. These are described below.

If the -e (--expression) option is given, its argument must be a valid Scheme expression. This expression will be evaluated for each statement matching the search criteria. Before evaluating, the global variable node is assigned the tree node describing the statement in question.

If both -f and -e options are given, the file supplied by the -f is loaded first and the expression will be evaluated for each node found.

In this case the file does not need to define cfpeek function as it will not be called implicitly, but it may do so, if this function is called from the expression.

These options are often used together to supply additional information to the script file. See the example 10 in the EXAMPLES section below.

  Node functions

(grecs-node? obj)
    Returns #t if obj is a valid Grecs node.

(grecs-node-root node)
    Returns the topmost node that can be traced up from node.

(grecs-node-head node)
    Returns the first node having the same parent and located on the same nesting level as node. I.e. the following always holds true:

    (let ((head (grecs-node-head node)))
     (and
      (eq? (grecs-node-up node) (grecs-node-up head))
      (not (grecs-node-prev? head))))

(grecs-node-tail node)
    Returns the last node having the same parent and located on the same nesting level as node. In other words, the following relation is always #t:

    (let ((tail (grecs-node-tail node)))
     (and
      (eq? (grecs-node-up node) (grecs-node-up tail))
      (not (grecs-node-next? tail))))

(grecs-node-up? node)
    Returns #t if node has a parent.

(grecs-node-up node)
    Returns the parent node of node.

(grecs-node-down? node)
    Returns #t if node has child nodes.

(grecs-node-down node)
    Returns the first child node of node.

(grecs-node-next? node)
    Returns #t if node is followed by another node on the same nesting level.

(grecs-node-next node)
    Returns the node following node on the same nesting level.

(grecs-node-prev? node)
    Returns #t if node is preceded by another node on the same nesting level.

(grecs-node-prev node)
    Returns the node preceding node on the same nesting level.

(grecs-node-ident node)
    Returns the identifier of the node.

(grecs-node-path node)
    Returns the full path to the node (a string).

(grecs-node-path-list node)
    Returns the full path to the node, converted to a list. Each list element corresponds to a subnode identifier. A subnode which has a tag is represented by a cons, whose car contains the subnode identifier, and cdr its value. For example, the following path:

     .foo.bar=x.baz

    is represented as

     '("foo" ("bar" . "x") "baz")

(grecs-node-type node)
    Returns the type of the node. The following constants are defined:

    grecs-node-root
        The node is a root node. The following is always #t:

        (and (= (grecs-node-type node) grecs-node-root)
             (not (grecs-node-up? node))
             (not (grecs-node-prev? node)))

    grecs-node-stmt
        The node is a simple statement. The following is always #t:

        (and (= (grecs-node-type node) grecs-node-stmt)
             (not (grecs-node-down? node)))

    grecs-node-block
        The node is a block statement.

(grecs-node-has-value? node)
    Returns #t if node has a non-empty value.

(grecs-node-value node)
    Returns the value of the node.

(grecs-node-locus node)
    Returns source location of the node. Returned value is a cons:

    (file-name . line-number)

(grecs-find-node node path)
    Return the first node whose path, is path. Start search from node.

(grecs-match-first node pattern)
    Return the first node whose path matches pattern. Start search from node.

(grecs-match-next node)
    Node must be a node returned by a previous call to grecs-match-first or grecs-match-next. The function grecs-match-next returns next node matching the initial pattern, or #f if no more nodes are found. For example, the following code iterates over all nodes matching pattern:

    (define (iterate-nodes root pattern thunk)
     (do ((node (grecs-match-first root pattern)
                (grecs-match-next node)))
         ((not node))
      (thunk node)))

EXIT STATUS
On normal termination, the exit status is 0. Exit status 1 indicates that not all search keys has been found. Exit codes greater than 1 indicate various error conditions:

2   Error parsing the input file.

3   Script failure.

64  The command was used incorrectly, e.g., with the wrong number of arguments, a bad option, a bad syntax in a parameter, or whatever.

69  The requested script file does not exist, contains syntax errors, or cannot be parsed for whatever other reason.

70  An internal software error has occurred. Please, report it, along with any error diagnostics produced by the program, if you ever stumble upon this error code.

78  The script file parses correctly, but does not define all the symbols required by cfpeek.

EXAMPLES

  1.
Print the entire contents of the /etc/dico.conf:

$ cfpeek /etc/dico.conf

  2.
Print contents of /etc/named.conf:

$ cfpeek --parser=bind /etc/named.conf

  3.
Print the value of the pid-file keyword from the options section of /etc/named.conf:

$ cfpeek --parser=bind /etc/named.conf .options.pid-file

The output will look like:

 .options.pid-file: /var/run/named.pid

To make it output only the value, without the keyword path, use the --format option:

$ cfpeek --parser=bind --format=value /etc/named.conf .options.pid-file

  4.
This is how to use the above in a startup/shutdown script to bring named down:

PIDFILE=`cfpeek --parser=bind --format=value \
         /etc/named.conf .options.pid-file`
if [ -R $PIDFILE ]
then
  kill -TERM `head -1 $PIDFILE`
fi

  5.
Find and print every occurrence of facility keyword in /etc/mailutils.rc(note the quotes):

$ cfpeek /etc/mailutils.rc '.*.facility'

  6.
The same, but print only the locations where the keyword occurred:

$ cfpeek --format=locus /etc/mailutils.rc .*.facility

  7.
Find the names of zone files for all master nodes in the named.conf file:

$ cfpeek --parser bind --format=sibling=file,value /etc/named.conf \\
'.*.zone.type=master'

See example 11 below, for another way of doing so.

  8.
Apply the script master-zone.scm to each statement from the file /etc/named.conf:

$ cfpeek --parser=bind --script=master-zone.scm /etc/named.conf .

Notice the final dot, which refers to the root of the parse tree.

  9.
Apply the script master-zone.scm to each zone statement which occurs within the view "external" section:

$ cfpeek --parser=bind --script=master-zone.scm /etc/named.conf \\
.view=external.zone

  10.
Same as above, but initialize additional parameters for the script:

$ cfpeek --parser=bind --script=master-zone.scm \\
--expression '(set! indent 8) (cfpeek node)' /etc/named.conf
.view=external.zone

Note the explicit call to cfpeek function.

  11.
Print the file name of each master zone in the /etc/named.conf file:

$ cfpeek --parser=bind -e '
(if (and (string=? (grecs-node-ident node) "type")
(string=? (grecs-node-value node) "master"))
(format #t "~A~%" (grecs-node-value
(grecs-find-node
(grecs-node-head node) "file"))))' \\
/etc/named.conf

SEE ALSO
grecs_stmt_path(5), grecs_config(5), m4(1).

The full documentation for cfpeek is maintained as a Texinfo manual. If the info and cfpeek programs are properly installed at your site, the command

    info cfpeek

should give you access to the complete manual.

An online copy of the latest cfpeek documentation is available from <http://www.gnu.org.ua/software/cfpeek>.

AUTHORS
Sergey Poznyakoff

BUG REPORTS
Report bugs to <bug-cfpeek@gnu.org.ua>.

COPYRIGHT
Copyright © 2011 Sergey Poznyakoff
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.