---
name: "bsdconf"
section: "3"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/bsdconf"
---

# bsdconf(3)

configuration file reading library

## NAME

**bsdconf**, **bsdconf\_parse**, **bsdconf\_fparse**, **bsdconf\_get\_option**, **bsdconf\_spool**, **bsdconf\_unquote** – configuration file reading library

## LIBRARY

library “libbsdconf”

## SYNOPSIS

**#include \<bsdconf.h\>**

*int*\

**bsdconf\_parse**(*struct bsdconf\_option options\[\]*, *const char \*path*, *int \*unknownstruct bsdconf\_option \*option*, *uint32\_t line*, *char \*directive*, *char \*value*, *uint16\_t processing\_options*);

*int*\

**bsdconf\_fparse**(*struct bsdconf\_option options\[\]*, *int fd*, *int \*unknownstruct bsdconf\_option \*option*, *uint32\_t line*, *char \*directive*, *char \*value*, *uint16\_t processing\_options*);

*struct bsdconf\_option \**\

**bsdconf\_get\_option**(*struct bsdconf\_option options\[\]*, *const char \*directive*);

*int*\

**bsdconf\_spool**(*int fd*);

*char \**\

**bsdconf\_unquote**(*char \*value*);

## DESCRIPTION

The **bsdconf** library provides a light-weight, portable framework for reading and writing configuration files. It is the successor to the retired **figpar** library, extending the original read-only token parser into a unified, resilient reader/writer engine.

Due to the fact that configuration files may have basic syntax differences, the library does not attempt to impose any structure on the data but instead provides raw data to a set of callback functions. These callback functions can in-turn initiate abort through their return value, allowing custom syntax validation during parsing.

Syntax differences between well-known file formats are described by format descriptors: a format descriptor is a small read-only table of properties (*struct* *bsdconf\_format\_def*; *see* [bsdconf\_format(3)](/bsdconf_format/3.md)) naming a format's target keyword, backing files, and tokenizing/quoting rules, which parameterize a single shared engine.

Despite the name, it bears no relation to a file descriptor; it is closer in spirit to a driver's method table: static data describing behavior, consulted rather than executed. Writing is documented in [bsdconf\_put(3)](/bsdconf_put/3.md); built-in formats and discovery in [bsdconf\_format(3)](/bsdconf_format/3.md).

Configuration directives, types, and callback functions are provided through data structures defined in ⟨bsdconf.h⟩:

```
struct bsdconf_option {
    enum bsdconf_type		type;	/* value type */
    const char			*directive; /* keyword */
    union bsdconf_value		value;	/* value */
    enum bsdconf_op		op;	/* assignment operator */
    uint8_t			action;	/* bsdconf_put() action */
    uint16_t			result;	/* set by bsdconf_put() */
    uint32_t			line;	/* set by bsdconf_put() */
    uint32_t			match_line;
					/* put: 0=any, else line */
    /* Pointer to function used when directive is found */
    int (*parse)(struct bsdconf_option *option, uint32_t line,
        char *directive, char *value);
};
enum bsdconf_type {
    BSDCONF_TYPE_NONE      = 0x0000, /* directives with no value */
    BSDCONF_TYPE_BOOL      = 0x0001, /* boolean */
    BSDCONF_TYPE_INT       = 0x0002, /* signed 32-bit integer */
    BSDCONF_TYPE_UINT      = 0x0004, /* unsigned 32-bit integer */
    BSDCONF_TYPE_STR       = 0x0008, /* string pointer */
    BSDCONF_TYPE_STRARRAY  = 0x0010, /* string array pointer */
    BSDCONF_TYPE_DATA1     = 0x0020, /* void data type-1 (open) */
    BSDCONF_TYPE_DATA2     = 0x0040, /* void data type-2 (open) */
    BSDCONF_TYPE_DATA3     = 0x0080, /* void data type-3 (open) */
    BSDCONF_TYPE_INT64     = 0x0100, /* signed 64-bit integer */
    BSDCONF_TYPE_UINT64    = 0x0200, /* unsigned 64-bit integer */
    BSDCONF_TYPE_RESERVED  = 0x0400, /* reserved */
};
union bsdconf_value {
    void	*data;      /* Opaque pointer (DATA1..DATA3) */
    char	*str;       /* Pointer to NUL-terminated string */
    char	**strarray; /* Pointer to an array of strings */
    int32_t	num;        /* Signed 32-bit integer value */
    uint32_t	u_num;      /* Unsigned 32-bit integer value */
    int64_t	num64;      /* Signed 64-bit integer value */
    uint64_t	u_num64;    /* Unsigned 64-bit integer value */
    bool	boolean;    /* Boolean value */
};
```

The *processing\_options* argument to **bsdconf\_parse**(), **bsdconf\_fparse**(), and [bsdconf\_put(3)](/bsdconf_put/3.md) is a mask of bit fields which indicate various processing options. The possible flags are:

- BSDCONF\_BREAK\_ON\_EQUALS

  An equals sign (‘=’) is normally considered part of the directive. This flag enables terminating the directive at the equals sign. Also makes equals sign optional and transient.

- BSDCONF\_BREAK\_ON\_SEMICOLON

  A semicolon (‘;’) is normally considered part of the value. This flag enables terminating the value at the semicolon. Also allows multiple statements on a single line separated by semicolon.

- BSDCONF\_CASE\_SENSITIVE

  Normally directives are matched case insensitively using [fnmatch(3)](/fnmatch/3.md). This flag enables directive matching to be case sensitive.

- BSDCONF\_REQUIRE\_EQUALS

  If a directive is not followed by an equals, processing is aborted.

- BSDCONF\_STRICT\_EQUALS

  Equals must be part of the directive (no whitespace before or after) to be considered a delimiter between directive and value. Required by file formats whose readers reject whitespace around the equals sign, such as the FreeBSD boot loader's processing of [loader.conf(5)](/loader.conf/5.md).

- BSDCONF\_OPERATOR\_EQUALS

  Recognize [make(1)](/make/1.md) style assignment modifiers( ‘+=’, ‘?=’, ‘:=’, and ‘!=’) and split them off the tail of the directive. The parsed operator is reported through the *op* member of the matched option (one of BSDCONF\_OP\_ASSIGN, BSDCONF\_OP\_APPEND, BSDCONF\_OP\_COND, BSDCONF\_OP\_EXPAND, or BSDCONF\_OP\_SHELL).

The *options* struct array pointer can be NULL and every directive will run the **unknown**() function argument.

The directive for each bsdconf\_option item in the **bsdconf\_parse**() options argument is matched against each parsed directive using [fnmatch(3)](/fnmatch/3.md) until a match is found. If a match is found, the **parse**() function for that bsdconf\_option directive is run with the line number, directive, and value. Otherwise if no match, the **unknown**() function is run (with the same arguments). When BSDCONF\_OPERATOR\_EQUALS is set, **unknown**() receives a non-NULL *option* whose *op* member holds the statement's assignment operator (there is no matched options-array slot to hang it on); otherwise *option* may be NULL.

If either **parse**() or **unknown**() return non-zero, **bsdconf\_parse**() aborts reading the file and returns the error value to its caller.

A value normally ends at the first unescaped newline, but a statement may span multiple lines: a backslash immediately preceding the newline continues the value on the next line, in the manner of [make(1)](/make/1.md) (essential to *make.conf* *and* *its* *siblings*). The backslash-newline pairs are removed from the value delivered to the callbacks (surrounding whitespace is preserved verbatim), and reported line numbers are those of each statement's first line. [bsdconf\_put(3)](/bsdconf_put/3.md) recognizes the same continuations when locating a value; rewriting a continued value replaces all of its lines with the single new value.

**bsdconf\_fparse**() is identical to **bsdconf\_parse**() except that it operates on an already-open file descriptor *fd*, which remains open on return (the caller retains ownership). The descriptor is read into a bounded in-memory buffer and then scanned as an array of characters (the same tokenizer used by [bsdconf\_put(3)](/bsdconf_put/3.md)). The buffer is capped at BSDCONF\_MAX\_BYTES\_DEFAULT bytes (67108864; 64 MiB); BSDCONF\_MAX\_BYTES overrides that ceiling (see ENVIRONMENT). Input larger than the cap fails with EFBIG. The descriptor need not be seekable; a pipe or socket is read to EOF subject to the same cap. This allows the caller to constrain the process (for example with [capsicum(4)](/capsicum/4.md)) before parsing begins.

**bsdconf\_spool**() copies the remaining contents of *fd* to an unlinked temporary file (created with [tmpfile(3)](/tmpfile/3.md)) and returns a seekable descriptor referencing it, which the caller must [close(2)](/close/2.md) (the backing storage is reclaimed then). It is exported for callers that need a seekable snapshot of a pipe or socket.

**bsdconf\_get\_option**() traverses the options-array and returns the option that matches via [strcmp(3)](/strcmp/3.md), or NULL if none matches.

**bsdconf\_unquote**() strips one layer of surrounding double-quotes from *value* in place and returns it. Parsed values retain their quotes so that data round-trips losslessly; this helper is for display and comparison purposes.

## RETURN VALUES

**bsdconf\_parse**() and **bsdconf\_fparse**() return zero on success; otherwise -1 (or the non-zero result of a callback) is returned and the global variable *errno* is set to indicate the error. Input that exceeds the BSDCONF\_MAX\_BYTES cap fails with EFBIG.

**bsdconf\_spool**() returns a new seekable file descriptor on success; otherwise -1 with *errno* set to indicate the error. **bsdconf\_get\_option**() returns a pointer to the matching option, or NULL when none matches.

## ENVIRONMENT

- BSDCONF\_MAX\_BYTES

  Maximum number of bytes **bsdconf\_fparse**() and **bsdconf\_put**() will read from a configuration file or stream. The default is BSDCONF\_MAX\_BYTES\_DEFAULT (67108864; 64 MiB). A larger value is an opt-in pain threshold for unusual files. Unset, empty, zero, or unparseable values restore the default.

## EXAMPLES

Read two known directives from a ‘name=value’ file, routing every statement through a callback:

```
#include <err.h>
#include <stdio.h>
#include <bsdconf.h>
static int
show(struct bsdconf_option *option, uint32_t line,
    char *directive, char *value)
{
	printf("%u: %s is %s\n", line, directive,
	    bsdconf_unquote(value));
	return (0);
}
static struct bsdconf_option options[] = {
	{ .directive = "hostname", .parse = show },
	{ .directive = "timeout",  .parse = show },
	{ .directive = NULL }
};
int
main(void)
{
	if (bsdconf_parse(options, "/usr/local/etc/myapp.conf",
	    NULL, BSDCONF_BREAK_ON_EQUALS) != 0)
		err(1, "myapp.conf");
	return (0);
}
```

Callbacks own the semantics, so a directive that legitimately repeats is accumulated rather than overwritten; no format descriptor is involved. The file here is Apache-style (space-separated, no equals sign), so BSDCONF\_BREAK\_ON\_EQUALS is simply omitted:

```
static char *servers[16];
static size_t nservers;
static int
addserver(struct bsdconf_option *option, uint32_t line,
    char *directive, char *value)
{
	if (nservers >= 16 ||
	    (servers[nservers] = strdup(value)) == NULL)
		return (-1); /* abort the parse */
	nservers++;
	return (0);
}
static struct bsdconf_option cumulative[] = {
	{ .directive = "server", .parse = addserver },
	{ .directive = NULL }
};
	...
	if (bsdconf_parse(cumulative, path, NULL, 0) != 0)
		err(1, "%s", path);
```

## SEE ALSO

[bsdconf\_format(3)](/bsdconf_format/3.md), [bsdconf\_put(3)](/bsdconf_put/3.md), [loader.conf(5)](/loader.conf/5.md), [sysctl.conf(5)](/sysctl.conf/5.md), [sysconf(8)](/sysconf/8.md)

## HISTORY

The **bsdconf** library first appeared in FreeBSD 16.0. It supersedes the **figpar** library which first appeared in FreeBSD 10.2 and was retired to the ports tree.

## AUTHORS

Devin Teske ⟨*dteske@FreeBSD.org*⟩ Faraz Vahedi ⟨*kfv@FreeBSD.org*⟩

## BUGS

This is the first implementation of the library, and the interface may be subject to refinement.

Write-path limitations for cumulative directives are discussed in the LIMITATIONS section of [bsdconf\_put(3)](/bsdconf_put/3.md).

## SECURITY CONSIDERATIONS

**bsdconf\_fparse**() reads the descriptor into a bounded in-memory buffer rather than trusting untrusted length fields, and accepts an already-open descriptor precisely so that a caller may sandbox itself (for example with [capsicum(4)](/capsicum/4.md)) before touching untrusted input, as [sysconf(8)](/sysconf/8.md) does for its read-only operations. The BSDCONF\_MAX\_BYTES cap (see ENVIRONMENT) is the bound on that buffer. Write-path hardening is documented in [bsdconf\_put(3)](/bsdconf_put/3.md).
