The Syntax and Structure of kunf Files

Lexical Rules

The lexical rules determine how a stream of characters is resolved into tokens. The kunf library uses a reasonably standard set of rules. It allows shell style comments (Anything between a hash ( # ) and a newline) and allows you to escape special characters.

Here is an itemized description of the rules. Where there appears a conflict between rules the earlier rule takes precedence:

  1. A sequence of characters is a single token if it delimited by double quotes.
  2. Characters following a hash are ignored until a newline is encountered.
  3. Whitespaces, unless part of a token enclosed by double quotes, only delimit tokens and are not tokens themselves.
  4. Tokens not enclosed by double quotes are delimited by whitespaces, angle brackets ( <> , square braces ( [] ), equal signs ( = ) and colons ( : ).
  5. Unless part of a token enclosed by double quotes the following characters are separate tokens: angle brackets, square braces, equal signs and colons.
  6. Characters preceded by a backslash ( \ ) or a percentage sign ( % ) have a special meaning. Backslash escapes can be used to escape newlines and quotes, while percentage escapes can be used to specify host, group and user specific attributes.

Percentage Escapes

These escapes are entirely transparent to the client program - in most cases the calling program will not be able (and should not need) to distinguish between generated and fixed values. These escapes allow the system administrator to construct a single configuration hierarchy. There is thus no need for the client program to explicitly parse global (/etc/foo.conf) and per user (~/.foorc) configuration files, since the system administrator can decide how to distribute configuration data between system-wide configuration files (rooted at /etc/root.kunf) and user files (such as ~/.foo.kunf).
%%
: Percentage Sign
%A
: Hardware Architecture
%D
: Domain Name
%G
: Real Group ID
%H
: Host Name
%N
: GECOS Field
%R
: Operating System Release
%U
: Real User ID
%V
: Operating System Version
%d
: Home Directory
%g
: Effective Group ID
%l
: Login Name
%o
: Operating System Name
%p
: Process ID
%s
: Login Shell
%u
: Effective User ID

Syntactic Rules

Grammar

The grammar obeys the following conventions: The grammar below applies to the root configuration file (/etc/root.kunf) and all redirected files. Included files have a more restricted grammar which is listed in the next part.

START ::= SECTION*
SECTION ::= HEADER ENTRIES*
HEADER ::= [ NAME [= redirected_file]]
NAME ::= part [: part]*
ENTRIES ::= (INCLUDE | PROPER_ENTRY)*
INCLUDE ::= < included_file >
PROPER_ENTRY ::= label = value [: comment]

The grammar of an included file is restricted to the following (meaning that you may not define new sections in an included file):

START ::= SECTION*
SECTION ::= ENTRIES*
ENTRIES ::= (INCLUDE | PROPER_ENTRY)*
INCLUDE ::= < include_file >
PROPER_ENTRY ::= label = value [: comment]

Redirection and Inclusion files

The kunf library stores its information in a set of files. How and where these are located is left to the system administrator, with only one exception: The file /etc/root.kunf is the starting point of any lookup. It is analogous to the root directory in a file system, where each section is a subdirectory, where the entries are regular files, and where redirection directives are comparable to mount points or symbolic links.

This setup makes it possible to for the system administrator to decide where to place configuration data. On the one extreme it is possible to keep all information in the /etc/root.kunf file, on the other it is possible to only keep redirection directives in the /etc/root.kunf file. The applications can be completely unaware of the location of the data.

Example Cases

Recall the C example which made use of the following sections:

[mail:foo:interface]
fgcolor="bright yellow"
bgcolor="blue"

[mail:foo:identity]
name="J. Soap"
signature="/home/jsoap/.signature"
replyto="jsoap@frogstar5.com"

[mail:foo:backend]
mailbox="/var/spool/mail/jsoap"
tmpdir="/var/tmp"

Using percentage escapes allows one to make these sections global:

[mail:foo:interface]
fgcolor="bright yellow"
bgcolor="blue"

[mail:foo:identity]
name=%N
signature="%d/.signature"
replyto="%l@frogstar5.com"

[mail:foo:backend]
mailbox="/var/spool/mail/%l"
tmpdir="/var/tmp"

And using redirection directives makes it possible to distribute this information over several files which can have different access permissions, so that different classes of users can modify or override them. In the following example the foo configuration data has been distributed over /etc/root.kunf, /etc/foo.kunf, /etc/foo.interface.kunf and ~/.foo.identity.

File /etc/root.kunf only redirects the lookup of mail:foo to file /etc/foo.kunf:


[mail:foo=/etc/foo.kunf]        # mail:foo redirected 
[news]                          # other sections start here
nntpserver="nntp.frogstar.com"  # proper entry (of form name=value)

File /etc/foo.kunf (Note that in this file the mail:foo part of the header should not be used since that has already been inherited from the header in /etc/foo.kunf):

[interface="/etc/foo.interface.kunf"]
                                # interface redirected
[identity]
<%d/.foo.identity>              # include per user config file
name=%N                         # fallback settings
signature="%d/.signature"
replyto="%l@frogstar5.com"

[backend]                       # these are fixed 
mailbox="/var/spool/mail/%l"
tmpdir="/var/tmp"

File /etc/foo.interface.kunf (here even the interface header should be omitted):

fgcolor="bright green"
bgcolor="grey"


File /home/jsoap/.foo.identity overrides the default settings for user jsoap:
name="Joe P Soap (Soaphead)"
signature="/home/jsoap/.funnysig"
replyto="soaphead@soapbox.net"
The net effect of distributing this configuration over several files is: And the interesting part is that the user program (foo) is unaware of this distributed configuration. No recoding needed. The example should not be able to distinguish between this configuration and one stored in a single file. Hopefully this explanation illustrates the power and convenience of the library. Otherwise have a look at the picture which depicts the relationship between the files since I do not feel like writing another thousand words.


The following image provides an indication of the internal representation of the configuration data. The data is stored as a tree, and information can either be looked up directly (see label Z where a single call extracts the value of a particular entry) or the tree can be navigated in a series of calls in a fashion similar to a normal directory structure (see label A, B, C and D). The dotted lines denote the effect of the function call, while solid arrows indicate the structure of the tree.


Next: Possible extensions