xref: /freebsd/lib/libbsdconf/bsdconf_format.3 (revision 3fe5961a0b708da599d42cbb6b5e4f030c28ea45)
1*3fe5961aSDevin Teske.\" Copyright (c) 2013-2026 Devin Teske <dteske@FreeBSD.org>
2*3fe5961aSDevin Teske.\" Copyright (c) 2021-2026 Faraz Vahedi <kfv@FreeBSD.org>
3*3fe5961aSDevin Teske.\"
4*3fe5961aSDevin Teske.\" SPDX-License-Identifier: BSD-2-Clause
5*3fe5961aSDevin Teske.\"
6*3fe5961aSDevin Teske.Dd August 2, 2026
7*3fe5961aSDevin Teske.Dt BSDCONF_FORMAT 3
8*3fe5961aSDevin Teske.Os
9*3fe5961aSDevin Teske.Sh NAME
10*3fe5961aSDevin Teske.Nm bsdconf_format_derive ,
11*3fe5961aSDevin Teske.Nm bsdconf_format_files ,
12*3fe5961aSDevin Teske.Nm bsdconf_format_files_free ,
13*3fe5961aSDevin Teske.Nm bsdconf_format_find ,
14*3fe5961aSDevin Teske.Nm bsdconf_format_guess ,
15*3fe5961aSDevin Teske.Nm bsdconf_format_lookup ,
16*3fe5961aSDevin Teske.Nm bsdconf_format_path ,
17*3fe5961aSDevin Teske.Nm bsdconf_format_processing ,
18*3fe5961aSDevin Teske.Nm bsdconf_format_put ,
19*3fe5961aSDevin Teske.Nm bsdconf_format_register
20*3fe5961aSDevin Teske.Nd configuration format descriptors and discovery
21*3fe5961aSDevin Teske.Sh LIBRARY
22*3fe5961aSDevin Teske.Lb libbsdconf
23*3fe5961aSDevin Teske.Sh SYNOPSIS
24*3fe5961aSDevin Teske.In bsdconf.h
25*3fe5961aSDevin Teske.Ft int
26*3fe5961aSDevin Teske.Fo bsdconf_format_derive
27*3fe5961aSDevin Teske.Fa "enum bsdconf_format base"
28*3fe5961aSDevin Teske.Fa "struct bsdconf_format_def *def"
29*3fe5961aSDevin Teske.Fc
30*3fe5961aSDevin Teske.Ft int
31*3fe5961aSDevin Teske.Fo bsdconf_format_files
32*3fe5961aSDevin Teske.Fa "enum bsdconf_format format"
33*3fe5961aSDevin Teske.Fa "const char *rootdir"
34*3fe5961aSDevin Teske.Fa "const char *module"
35*3fe5961aSDevin Teske.Fa "const char *defaults"
36*3fe5961aSDevin Teske.Fa "char ***filesp"
37*3fe5961aSDevin Teske.Fa "size_t *nfilesp"
38*3fe5961aSDevin Teske.Fa "size_t *write_idxp"
39*3fe5961aSDevin Teske.Fc
40*3fe5961aSDevin Teske.Ft void
41*3fe5961aSDevin Teske.Fo bsdconf_format_files_free
42*3fe5961aSDevin Teske.Fa "char **files"
43*3fe5961aSDevin Teske.Fa "size_t nfiles"
44*3fe5961aSDevin Teske.Fc
45*3fe5961aSDevin Teske.Ft int
46*3fe5961aSDevin Teske.Fo bsdconf_format_find
47*3fe5961aSDevin Teske.Fa "const char *keyword"
48*3fe5961aSDevin Teske.Fa "enum bsdconf_format *format"
49*3fe5961aSDevin Teske.Fc
50*3fe5961aSDevin Teske.Ft "enum bsdconf_format"
51*3fe5961aSDevin Teske.Fo bsdconf_format_guess
52*3fe5961aSDevin Teske.Fa "const char *path"
53*3fe5961aSDevin Teske.Fc
54*3fe5961aSDevin Teske.Ft "const struct bsdconf_format_def *"
55*3fe5961aSDevin Teske.Fo bsdconf_format_lookup
56*3fe5961aSDevin Teske.Fa "enum bsdconf_format format"
57*3fe5961aSDevin Teske.Fc
58*3fe5961aSDevin Teske.Ft "const char *"
59*3fe5961aSDevin Teske.Fo bsdconf_format_path
60*3fe5961aSDevin Teske.Fa "enum bsdconf_format format"
61*3fe5961aSDevin Teske.Fc
62*3fe5961aSDevin Teske.Ft uint16_t
63*3fe5961aSDevin Teske.Fo bsdconf_format_processing
64*3fe5961aSDevin Teske.Fa "enum bsdconf_format format"
65*3fe5961aSDevin Teske.Fc
66*3fe5961aSDevin Teske.Ft uint16_t
67*3fe5961aSDevin Teske.Fo bsdconf_format_put
68*3fe5961aSDevin Teske.Fa "enum bsdconf_format format"
69*3fe5961aSDevin Teske.Fc
70*3fe5961aSDevin Teske.Ft int
71*3fe5961aSDevin Teske.Fo bsdconf_format_register
72*3fe5961aSDevin Teske.Fa "const struct bsdconf_format_def *def"
73*3fe5961aSDevin Teske.Fa "enum bsdconf_format *format"
74*3fe5961aSDevin Teske.Fc
75*3fe5961aSDevin Teske.Sh DESCRIPTION
76*3fe5961aSDevin TeskeEvery supported configuration file format is described by the same small
77*3fe5961aSDevin Teskeformat descriptor
78*3fe5961aSDevin Teske.Pq introduced in Xr bsdconf 3 :
79*3fe5961aSDevin Teske.Bd -literal -offset indent
80*3fe5961aSDevin Teskestruct bsdconf_format_def {
81*3fe5961aSDevin Teske    const char	*keyword;    /* target keyword (or NULL) */
82*3fe5961aSDevin Teske    const char	*path;       /* default write path (or NULL) */
83*3fe5961aSDevin Teske    const struct bsdconf_source
84*3fe5961aSDevin Teske		*sources;    /* ordered sources (or NULL) */
85*3fe5961aSDevin Teske    const char	*defaults;   /* defaults file (or NULL) */
86*3fe5961aSDevin Teske    const char	*defaults_env;     /* environment override */
87*3fe5961aSDevin Teske    const char	*files_directive;
88*3fe5961aSDevin Teske			     /* directive listing conf files */
89*3fe5961aSDevin Teske    const char	*dirs_directive;
90*3fe5961aSDevin Teske			     /* directive listing drop-in dirs */
91*3fe5961aSDevin Teske    const char	*local_directive;
92*3fe5961aSDevin Teske			     /* directive listing local files */
93*3fe5961aSDevin Teske    uint16_t	processing;  /* processing_options bitmask */
94*3fe5961aSDevin Teske    uint16_t	put;         /* put_options bitmask */
95*3fe5961aSDevin Teske};
96*3fe5961aSDevin Teske
97*3fe5961aSDevin Teskeenum bsdconf_source_type {
98*3fe5961aSDevin Teske    BSDCONF_SOURCE_FILE = 0,  /* a single file */
99*3fe5961aSDevin Teske    BSDCONF_SOURCE_DIR,       /* each `*.conf' in a directory */
100*3fe5961aSDevin Teske    BSDCONF_SOURCE_MODDIR,    /* `<module>.conf' in a directory */
101*3fe5961aSDevin Teske};
102*3fe5961aSDevin Teske
103*3fe5961aSDevin Teskestruct bsdconf_source {
104*3fe5961aSDevin Teske    enum bsdconf_source_type type;  /* how to interpret path */
105*3fe5961aSDevin Teske    const char	*path;              /* file or directory path */
106*3fe5961aSDevin Teske};
107*3fe5961aSDevin Teske.Ed
108*3fe5961aSDevin Teske.Pp
109*3fe5961aSDevin TeskeThere is exactly one parsing and writing engine;
110*3fe5961aSDevin Teskea format descriptor merely parameterizes it.
111*3fe5961aSDevin TeskeThe built-in formats,
112*3fe5961aSDevin Teskewith their target keywords and default write paths,
113*3fe5961aSDevin Teskeare:
114*3fe5961aSDevin Teske.Bl -column "BSDCONF_FORMAT_GENERIC" "keyword" "/boot/loader.conf"
115*3fe5961aSDevin Teske.It Sy format Ta Sy keyword Ta Sy "default write path"
116*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_GENERIC Ta generic Ta \&-
117*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_LOADER Ta loader Ta /boot/loader.conf
118*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_SYSCTL Ta sysctl Ta /etc/sysctl.conf
119*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_MAKE Ta make Ta /etc/make.conf
120*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_SRC Ta src Ta /etc/src.conf
121*3fe5961aSDevin Teske.El
122*3fe5961aSDevin Teske.Pp
123*3fe5961aSDevin TeskeThe default write path
124*3fe5961aSDevin Teske.Pq the Va path member
125*3fe5961aSDevin Teskeanswers only the question of where a
126*3fe5961aSDevin Teske.Em new
127*3fe5961aSDevin Teskedirective lands:
128*3fe5961aSDevin Teskethe file to which a directive not yet present anywhere is appended.
129*3fe5961aSDevin TeskeWhich files are
130*3fe5961aSDevin Teske.Em consulted
131*3fe5961aSDevin Teskeis a separate and potentially broader question,
132*3fe5961aSDevin Teskeanswered by the
133*3fe5961aSDevin Teske.Va sources
134*3fe5961aSDevin Teskemember.
135*3fe5961aSDevin TeskeWhen
136*3fe5961aSDevin Teske.Va sources
137*3fe5961aSDevin Teskeis NULL
138*3fe5961aSDevin Teske.Pq as for Dv BSDCONF_FORMAT_MAKE
139*3fe5961aSDevin Teskethe default write path is the format's one and only file and the two
140*3fe5961aSDevin Teskequestions collapse into one.
141*3fe5961aSDevin TeskeOtherwise
142*3fe5961aSDevin Teske.Po
143*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_LOADER ,
144*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_SYSCTL ,
145*3fe5961aSDevin Teskeand
146*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_SRC
147*3fe5961aSDevin Teske.Pc
148*3fe5961aSDevin Teskethe format is backed by several files and
149*3fe5961aSDevin Teske.Va sources
150*3fe5961aSDevin Teskelists them:
151*3fe5961aSDevin Teskean ordered,
152*3fe5961aSDevin TeskeNULL-path terminated array in which each entry contributes a single file
153*3fe5961aSDevin Teske.Pq Dv BSDCONF_SOURCE_FILE ,
154*3fe5961aSDevin Teskeevery
155*3fe5961aSDevin Teske.Ql *.conf
156*3fe5961aSDevin Teskefound in a drop-in directory
157*3fe5961aSDevin Teske.Pq Dv BSDCONF_SOURCE_DIR ,
158*3fe5961aSDevin Teskeor the file
159*3fe5961aSDevin Teske.Ql <module>.conf
160*3fe5961aSDevin Teskein a directory keyed by kernel module name
161*3fe5961aSDevin Teske.Pq Dv BSDCONF_SOURCE_MODDIR .
162*3fe5961aSDevin TeskeThe order matches the order in which the system sources the files at boot,
163*3fe5961aSDevin Teskeso a directive in a later file overrides the same directive in an earlier
164*3fe5961aSDevin Teskeone and the last file listing a directive is the authoritative source of
165*3fe5961aSDevin Teskeits value.
166*3fe5961aSDevin TeskeThe built-in source lists are:
167*3fe5961aSDevin Teske.Bl -tag -width BSDCONF_FORMAT_LOADER -offset indent
168*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_LOADER
169*3fe5961aSDevin Teskediscovered from
170*3fe5961aSDevin Teske.Pa /boot/defaults/loader.conf
171*3fe5961aSDevin Teske.Pq see below ;
172*3fe5961aSDevin Teskeon a stock system
173*3fe5961aSDevin Teske.Pa /boot/device.hints ,
174*3fe5961aSDevin Teske.Pa /boot/loader.conf ,
175*3fe5961aSDevin Teskeeach
176*3fe5961aSDevin Teske.Pa *.conf
177*3fe5961aSDevin Teskein
178*3fe5961aSDevin Teske.Pa /boot/loader.conf.d ,
179*3fe5961aSDevin Teskethen
180*3fe5961aSDevin Teske.Pa /boot/loader.conf.local
181*3fe5961aSDevin Teske.Pq see Xr loader.conf 5 ;
182*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_SYSCTL
183*3fe5961aSDevin Teske.Pa /etc/sysctl.conf ,
184*3fe5961aSDevin Teske.Pa /etc/sysctl.conf.local ,
185*3fe5961aSDevin Teskethen
186*3fe5961aSDevin Teske.Pa /etc/sysctl.kld.d/<module>.conf
187*3fe5961aSDevin Teske.Pq see Xr sysctl.conf 5 ;
188*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_MAKE
189*3fe5961aSDevin Teske.Pa /etc/make.conf
190*3fe5961aSDevin Teskealone;
191*3fe5961aSDevin Teske.It Dv BSDCONF_FORMAT_SRC
192*3fe5961aSDevin Teske.Pa /etc/src-env.conf ,
193*3fe5961aSDevin Teske.Pa /etc/make.conf ,
194*3fe5961aSDevin Teskethen
195*3fe5961aSDevin Teske.Pa /etc/src.conf
196*3fe5961aSDevin Teske.Pq the /usr/src build triad; see Xr src.conf 5 ;
197*3fe5961aSDevin Teskenew writes prefer
198*3fe5961aSDevin Teske.Pa src.conf .
199*3fe5961aSDevin Teske.El
200*3fe5961aSDevin Teske.Pp
201*3fe5961aSDevin TeskeA format whose backing files are themselves configuration data describes
202*3fe5961aSDevin Teskethat machinery with the descriptor's
203*3fe5961aSDevin Teske.Va defaults
204*3fe5961aSDevin Teskemember quintet rather than a static list alone.
205*3fe5961aSDevin TeskeThe boot loader hardcodes only
206*3fe5961aSDevin Teske.Pa /boot/defaults/loader.conf
207*3fe5961aSDevin Teskeand discovers every other file from the
208*3fe5961aSDevin Teske.Va loader_conf_files ,
209*3fe5961aSDevin Teske.Va loader_conf_dirs ,
210*3fe5961aSDevin Teskeand
211*3fe5961aSDevin Teske.Va local_loader_conf_files
212*3fe5961aSDevin Teskedirectives it encounters along the way
213*3fe5961aSDevin Teske.Pq see Xr loader.conf 5 ,
214*3fe5961aSDevin Teskeand
215*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_LOADER
216*3fe5961aSDevin Teskenames that defaults file and those three directives so that
217*3fe5961aSDevin Teske.Fn bsdconf_format_files
218*3fe5961aSDevin Teskematches that discovery:
219*3fe5961aSDevin Teskethe defaults file is read,
220*3fe5961aSDevin Teske.Va loader_conf_files
221*3fe5961aSDevin Teskeis chased
222*3fe5961aSDevin Teske.Po
223*3fe5961aSDevin Teskere-read after every file, as the loader does when a file queues
224*3fe5961aSDevin Teskeadditional names
225*3fe5961aSDevin Teske.Pc ,
226*3fe5961aSDevin Teskeand the drop-in directories and local files named by the final
227*3fe5961aSDevin Teske.Va loader_conf_dirs
228*3fe5961aSDevin Teskeand
229*3fe5961aSDevin Teske.Va local_loader_conf_files
230*3fe5961aSDevin Teskevalues are appended
231*3fe5961aSDevin Teske.Pq the loader likewise applies those only after the file-list walk .
232*3fe5961aSDevin TeskeThe defaults file itself is deliberately excluded from the resolved list,
233*3fe5961aSDevin Teskemirroring how
234*3fe5961aSDevin Teske.Xr sysrc 8
235*3fe5961aSDevin Teskeexcludes
236*3fe5961aSDevin Teske.Pa /etc/defaults/rc.conf ;
237*3fe5961aSDevin Teskethe static
238*3fe5961aSDevin Teske.Va sources
239*3fe5961aSDevin Teskelist serves as the fallback when the defaults file is missing.
240*3fe5961aSDevin Teske.Pp
241*3fe5961aSDevin Teske.Fn bsdconf_format_files
242*3fe5961aSDevin Teskeresolves the backing files of
243*3fe5961aSDevin Teske.Fa format
244*3fe5961aSDevin Teskeinto a newly allocated array of paths stored through
245*3fe5961aSDevin Teske.Fa filesp
246*3fe5961aSDevin Teske.Pq with the count stored through Fa nfilesp ,
247*3fe5961aSDevin Teskeeach prefixed with
248*3fe5961aSDevin Teske.Fa rootdir
249*3fe5961aSDevin Teskeunless NULL or empty.
250*3fe5961aSDevin TeskeWhen
251*3fe5961aSDevin Teske.Fa defaults
252*3fe5961aSDevin Teskeis non-NULL,
253*3fe5961aSDevin Teskeit overrides the descriptor's defaults file for discovery and is used
254*3fe5961aSDevin Teskeverbatim
255*3fe5961aSDevin Teske.Po
256*3fe5961aSDevin Teskenot prefixed with
257*3fe5961aSDevin Teske.Fa rootdir ;
258*3fe5961aSDevin Teskeit is ignored for formats without one
259*3fe5961aSDevin Teske.Pc .
260*3fe5961aSDevin TeskeWhen
261*3fe5961aSDevin Teske.Fa write_idxp
262*3fe5961aSDevin Teskeis non-NULL,
263*3fe5961aSDevin Teskethe index of the file recommended for directives found in no file at all
264*3fe5961aSDevin Teskeis stored through it:
265*3fe5961aSDevin Teskethe format's default write path,
266*3fe5961aSDevin Teskeor the last regular
267*3fe5961aSDevin Teske.Pq non-drop-in, non-local
268*3fe5961aSDevin Teskeconfiguration file when discovery is in play.
269*3fe5961aSDevin TeskeSources of type
270*3fe5961aSDevin Teske.Dv BSDCONF_SOURCE_FILE
271*3fe5961aSDevin Teske.Pq and files named by a file-list directive
272*3fe5961aSDevin Teskeare always listed,
273*3fe5961aSDevin Teskewhether or not the file exists;
274*3fe5961aSDevin Teskedirectory sources contribute only the entries present on disk
275*3fe5961aSDevin Teske.Pq sorted ;
276*3fe5961aSDevin Teskemodule sources contribute
277*3fe5961aSDevin Teske.Ql <module>.conf
278*3fe5961aSDevin Teskeonly when
279*3fe5961aSDevin Teske.Fa module
280*3fe5961aSDevin Teskeis non-NULL.
281*3fe5961aSDevin TeskeThe caller releases the result with
282*3fe5961aSDevin Teske.Fn bsdconf_format_files_free .
283*3fe5961aSDevin Teske.Pp
284*3fe5961aSDevin TeskeThe formats also differ in quoting on output,
285*3fe5961aSDevin Teskeeach honoring the full syntax its consumer accepts:
286*3fe5961aSDevin Teske.Xr loader.conf 5
287*3fe5961aSDevin Teskevalues are always written quoted
288*3fe5961aSDevin Teske.Pq quoted or unquoted input is accepted when parsing
289*3fe5961aSDevin Teskeand no whitespace is permitted around the equals sign,
290*3fe5961aSDevin Teskeas demanded by the boot loader's reader;
291*3fe5961aSDevin Teske.Xr sysctl.conf 5
292*3fe5961aSDevin Teskefollows the file parser of
293*3fe5961aSDevin Teske.Xr sysctl 8 ,
294*3fe5961aSDevin Teskewhich trims whitespace around the equals sign and strips one pair of quotes
295*3fe5961aSDevin Teskearound the value,
296*3fe5961aSDevin Teskeso values are written unquoted unless quoting is required
297*3fe5961aSDevin Teske.Pq embedded whitespace or a comment character ;
298*3fe5961aSDevin Teske.Pa make.conf
299*3fe5961aSDevin Teskefollows
300*3fe5961aSDevin Teske.Xr make 1
301*3fe5961aSDevin Teskesyntax where values are never quoted
302*3fe5961aSDevin Teske.Pq the value runs to the end of the line
303*3fe5961aSDevin Teskeand assignment modifiers such as
304*3fe5961aSDevin Teske.Ql +=
305*3fe5961aSDevin Teskeare recognized.
306*3fe5961aSDevin TeskeThe
307*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_SRC
308*3fe5961aSDevin Tesketriad
309*3fe5961aSDevin Teske.Po
310*3fe5961aSDevin Teske.Pa src-env.conf ,
311*3fe5961aSDevin Teske.Pa make.conf ,
312*3fe5961aSDevin Teske.Pa src.conf
313*3fe5961aSDevin Teske.Pc
314*3fe5961aSDevin Teskeshares that
315*3fe5961aSDevin Teske.Pa make.conf
316*3fe5961aSDevin Teskesyntax exactly
317*3fe5961aSDevin Teske.Pq all three are read by Xr make 1 when building /usr/src ,
318*3fe5961aSDevin Teskeincluding the empty value,
319*3fe5961aSDevin Teskewhich for
320*3fe5961aSDevin Teske.Pa src.conf
321*3fe5961aSDevin Teskeis the idiom for the value-less
322*3fe5961aSDevin Teske.Ql WITH_*
323*3fe5961aSDevin Teskeand
324*3fe5961aSDevin Teske.Ql WITHOUT_*
325*3fe5961aSDevin Teskebuild knobs.
326*3fe5961aSDevin Teske.Pp
327*3fe5961aSDevin Teske.Fn bsdconf_format_find
328*3fe5961aSDevin Teskemaps a target keyword
329*3fe5961aSDevin Teske.Pq e.g., Dq loader
330*3fe5961aSDevin Tesketo its format.
331*3fe5961aSDevin Teske.Fn bsdconf_format_guess
332*3fe5961aSDevin Teskeguesses the format of an arbitrary file from the basename of
333*3fe5961aSDevin Teske.Fa path ,
334*3fe5961aSDevin Teskematching
335*3fe5961aSDevin Teske.Ql <keyword>.conf
336*3fe5961aSDevin Teskewith an optional trailing suffix
337*3fe5961aSDevin Teske.Pq e.g., Pa /etc/sysctl.conf.local .
338*3fe5961aSDevin TeskeThe guess is advisory and offered for consumers that opt into it
339*3fe5961aSDevin Teske.Pq an interactive picker suggesting a default, for example ;
340*3fe5961aSDevin Teskewhere a wrong format silently misformats a file,
341*3fe5961aSDevin Teskeas when writing,
342*3fe5961aSDevin Teskethe caller should require the format to be stated explicitly instead,
343*3fe5961aSDevin Teskeas
344*3fe5961aSDevin Teske.Xr sysconf 8
345*3fe5961aSDevin Teskedoes with its
346*3fe5961aSDevin Teske.Ar target
347*3fe5961aSDevin Teskekeyword.
348*3fe5961aSDevin Teske.Fn bsdconf_format_lookup
349*3fe5961aSDevin Teskereturns the format descriptor for a format handle.
350*3fe5961aSDevin Teske.Fn bsdconf_format_path ,
351*3fe5961aSDevin Teske.Fn bsdconf_format_processing ,
352*3fe5961aSDevin Teskeand
353*3fe5961aSDevin Teske.Fn bsdconf_format_put
354*3fe5961aSDevin Teskereturn the default file path and the two option bitmasks,
355*3fe5961aSDevin Teskerespectively.
356*3fe5961aSDevin Teske.Sh ADDING FORMATS
357*3fe5961aSDevin TeskeBefore adding a format,
358*3fe5961aSDevin Teskeconsider whether one is needed at all:
359*3fe5961aSDevin Teskethe parser hands each statement's raw directive and value to the caller's
360*3fe5961aSDevin Teskecallbacks and imposes no semantics of its own,
361*3fe5961aSDevin Teskeso a file whose directives mean something unusual
362*3fe5961aSDevin Teske.Po
363*3fe5961aSDevin Teskecumulative directives that legitimately repeat,
364*3fe5961aSDevin Teskefor example,
365*3fe5961aSDevin Teskewhich a
366*3fe5961aSDevin Teske.Fn parse
367*3fe5961aSDevin Teskecallback accumulates rather than overwrites;
368*3fe5961aSDevin Teskesee
369*3fe5961aSDevin Teske.Xr bsdconf 3
370*3fe5961aSDevin Teske.Pc
371*3fe5961aSDevin Teskeis read with the stock engine and bespoke callbacks;
372*3fe5961aSDevin Teskeno format descriptor,
373*3fe5961aSDevin Teskeflag,
374*3fe5961aSDevin Teskeor engine change is required.
375*3fe5961aSDevin TeskeA format descriptor parameterizes only tokenization and writing;
376*3fe5961aSDevin Teskereach for one when a file needs a
377*3fe5961aSDevin Teske.Xr sysconf 8
378*3fe5961aSDevin Tesketarget keyword,
379*3fe5961aSDevin Teskea source list,
380*3fe5961aSDevin Teskeor distinct quoting on output.
381*3fe5961aSDevin TeskeRewriting files built from cumulative directives,
382*3fe5961aSDevin Teskewhere a change is additive rather than a replacement,
383*3fe5961aSDevin Teskeis only partly covered by
384*3fe5961aSDevin Teske.Va match_line
385*3fe5961aSDevin Teskeselection in
386*3fe5961aSDevin Teske.Xr bsdconf_put 3 ;
387*3fe5961aSDevin Teskehigher-level additive policy remains the caller's concern
388*3fe5961aSDevin Teske.Pq see that page's Sx LIMITATIONS .
389*3fe5961aSDevin Teske.Pp
390*3fe5961aSDevin TeskeBeyond callbacks,
391*3fe5961aSDevin Teskethe format descriptor is the entire definition of a format;
392*3fe5961aSDevin Teskeno format has private parsing or writing code.
393*3fe5961aSDevin TeskeSupport for a new configuration file format is therefore a data problem,
394*3fe5961aSDevin Teskeapproached one of two ways.
395*3fe5961aSDevin Teske.Pp
396*3fe5961aSDevin TeskeAn application whose format is mostly like an existing one bolts it on at
397*3fe5961aSDevin Teskeruntime without duplicating any logic
398*3fe5961aSDevin Teske.Pq see Sx EXAMPLES :
399*3fe5961aSDevin Teske.Fn bsdconf_format_derive
400*3fe5961aSDevin Teskecopies the format descriptor of the nearest
401*3fe5961aSDevin Teske.Fa base
402*3fe5961aSDevin Teskeformat into
403*3fe5961aSDevin Teske.Fa def ,
404*3fe5961aSDevin Teskethe caller adjusts only the members that differ
405*3fe5961aSDevin Teske.Pq typically the keyword, the paths, and one or two bitmask flags ,
406*3fe5961aSDevin Teskeand
407*3fe5961aSDevin Teske.Fn bsdconf_format_register
408*3fe5961aSDevin Teskeregisters the result and returns a new format handle through
409*3fe5961aSDevin Teske.Fa format .
410*3fe5961aSDevin TeskeThe format descriptor is copied by value but the strings and arrays it
411*3fe5961aSDevin Teskereferences
412*3fe5961aSDevin Teske.Po
413*3fe5961aSDevin Teske.Va keyword ,
414*3fe5961aSDevin Teske.Va path ,
415*3fe5961aSDevin Teske.Va sources ,
416*3fe5961aSDevin Teskeand the
417*3fe5961aSDevin Teske.Va defaults
418*3fe5961aSDevin Teskemember quintet
419*3fe5961aSDevin Teske.Pc
420*3fe5961aSDevin Teskeare not;
421*3fe5961aSDevin Teskethey must remain valid for the life of the registration.
422*3fe5961aSDevin TeskeRegistered formats participate in keyword and basename resolution exactly
423*3fe5961aSDevin Teskelike built-ins,
424*3fe5961aSDevin Teskeincluding target resolution in
425*3fe5961aSDevin Teske.Xr sysconf 8 Ns -style
426*3fe5961aSDevin Teskeconsumers.
427*3fe5961aSDevin TeskeRegistration is intended to occur during program initialization and is not
428*3fe5961aSDevin Teskethread-safe.
429*3fe5961aSDevin Teske.Pp
430*3fe5961aSDevin TeskeWithin the library,
431*3fe5961aSDevin Teskeeach built-in format is a self-contained translation unit
432*3fe5961aSDevin Teske.Pa ( bsdconf_format_<keyword>.c )
433*3fe5961aSDevin Teskethat documents the format's syntax rules,
434*3fe5961aSDevin Teskecites the authority for them
435*3fe5961aSDevin Teske.Pq the consumer whose reader defines what is legal ,
436*3fe5961aSDevin Teskeand defines its format descriptor,
437*3fe5961aSDevin Teskeincluding its ordered source list.
438*3fe5961aSDevin TeskePromoting a format into the library therefore touches no existing parsing
439*3fe5961aSDevin Teskeor writing code:
440*3fe5961aSDevin Teskea new file of the same shape is dropped in,
441*3fe5961aSDevin Teskeits descriptor is declared alongside its siblings,
442*3fe5961aSDevin Teskeone
443*3fe5961aSDevin Teske.Dv BSDCONF_FORMAT_*
444*3fe5961aSDevin Teskeconstant is appended to
445*3fe5961aSDevin Teske.Vt enum bsdconf_format ,
446*3fe5961aSDevin Teskeone pointer is appended to the registry table,
447*3fe5961aSDevin Teskethe file is listed in the Makefile,
448*3fe5961aSDevin Teskeand this manual's
449*3fe5961aSDevin Teske.Sx DESCRIPTION
450*3fe5961aSDevin Teskesection grows one row and one quoting note.
451*3fe5961aSDevin TeskeThe keyword becomes a
452*3fe5961aSDevin Teske.Xr sysconf 8
453*3fe5961aSDevin Tesketarget automatically.
454*3fe5961aSDevin Teske.Pp
455*3fe5961aSDevin TeskeMany formats need no new engine capability at all.
456*3fe5961aSDevin TeskeFormats whose statements are a space-separated directive and value with no
457*3fe5961aSDevin Teskeequals sign
458*3fe5961aSDevin Teske.Pq the Apache-style directive files the ancestral parser was raised on
459*3fe5961aSDevin Teskeparse today:
460*3fe5961aSDevin Teskewith
461*3fe5961aSDevin Teske.Dv BSDCONF_BREAK_ON_EQUALS
462*3fe5961aSDevin Teskeomitted,
463*3fe5961aSDevin Teskethe first whitespace-delimited token is the directive and the remainder of
464*3fe5961aSDevin Teskethe line is the raw value
465*3fe5961aSDevin Teske.Po which a
466*3fe5961aSDevin Teske.Fn parse
467*3fe5961aSDevin Teskecallback may split further by its own rules
468*3fe5961aSDevin Teske.Pc ,
469*3fe5961aSDevin Teskeand directive matching is case insensitive unless
470*3fe5961aSDevin Teske.Dv BSDCONF_CASE_SENSITIVE
471*3fe5961aSDevin Teskeis set.
472*3fe5961aSDevin TeskeLikewise
473*3fe5961aSDevin Teske.Dv BSDCONF_BREAK_ON_SEMICOLON
474*3fe5961aSDevin Teskealready covers formats that terminate or chain statements with a
475*3fe5961aSDevin Teskesemicolon.
476*3fe5961aSDevin Teske.Pp
477*3fe5961aSDevin TeskeA candidate format whose syntax the existing option flags cannot express
478*3fe5961aSDevin Teske.Pq brace-grouped statement blocks being the canonical example
479*3fe5961aSDevin Teskeis handled by teaching the shared engine
480*3fe5961aSDevin Teske.Pq the scanners in the parsing and writing cores
481*3fe5961aSDevin Teskeone new
482*3fe5961aSDevin Teske.Va processing
483*3fe5961aSDevin Teskeor
484*3fe5961aSDevin Teske.Va put
485*3fe5961aSDevin Teskeflag that the new format's descriptor is the first to set.
486*3fe5961aSDevin TeskeThe capability lands once,
487*3fe5961aSDevin Teskecomposes with every existing flag,
488*3fe5961aSDevin Teskeand becomes available to every other format
489*3fe5961aSDevin Teske.Pq built-in, derived, or registered
490*3fe5961aSDevin Teskerather than living in a private parser;
491*3fe5961aSDevin Teskethe new format itself remains nothing more than a format descriptor in its
492*3fe5961aSDevin Teskeown translation unit.
493*3fe5961aSDevin Teske.Sh RETURN VALUES
494*3fe5961aSDevin Teske.Fn bsdconf_format_derive
495*3fe5961aSDevin Teskeand
496*3fe5961aSDevin Teske.Fn bsdconf_format_register
497*3fe5961aSDevin Teskereturn zero on success;
498*3fe5961aSDevin Teskeotherwise -1 with
499*3fe5961aSDevin Teske.Va errno
500*3fe5961aSDevin Teskeset to
501*3fe5961aSDevin Teske.Er EINVAL
502*3fe5961aSDevin Teskeor
503*3fe5961aSDevin Teske.Er ENOSPC .
504*3fe5961aSDevin Teske.Fn bsdconf_format_find
505*3fe5961aSDevin Teskereturns zero on success;
506*3fe5961aSDevin Teskeotherwise -1.
507*3fe5961aSDevin Teske.Fn bsdconf_format_files
508*3fe5961aSDevin Teskereturns zero on success;
509*3fe5961aSDevin Teskeotherwise -1 with
510*3fe5961aSDevin Teske.Va errno
511*3fe5961aSDevin Teskeset to indicate the error
512*3fe5961aSDevin Teske.Pq Er EINVAL for a format with no backing files .
513*3fe5961aSDevin Teske.Sh EXAMPLES
514*3fe5961aSDevin TeskeBolt on a new format at runtime by deriving from the built-in it most
515*3fe5961aSDevin Teskeresembles,
516*3fe5961aSDevin Teskethen set a directive in its file with full resilient write semantics:
517*3fe5961aSDevin Teske.Bd -literal -offset indent
518*3fe5961aSDevin Teskestruct bsdconf_format_def def;
519*3fe5961aSDevin Teskeenum bsdconf_format myfmt;
520*3fe5961aSDevin Teskestruct bsdconf_option set[] = {
521*3fe5961aSDevin Teske	{ .type = BSDCONF_TYPE_STR, .directive = "loglevel",
522*3fe5961aSDevin Teske	  .value = { .str = "debug" },
523*3fe5961aSDevin Teske	  .action = BSDCONF_ACTION_SET_VALUE },
524*3fe5961aSDevin Teske	{ .directive = NULL }
525*3fe5961aSDevin Teske};
526*3fe5961aSDevin Teske
527*3fe5961aSDevin Teskeif (bsdconf_format_derive(BSDCONF_FORMAT_SYSCTL, &def) != 0)
528*3fe5961aSDevin Teske	err(1, "bsdconf_format_derive");
529*3fe5961aSDevin Teskedef.keyword = "myapp";
530*3fe5961aSDevin Teskedef.path = "/usr/local/etc/myapp.conf";
531*3fe5961aSDevin Teskedef.sources = NULL;	/* one file; path is the sole source */
532*3fe5961aSDevin Teskeif (bsdconf_format_register(&def, &myfmt) != 0)
533*3fe5961aSDevin Teske	err(1, "bsdconf_format_register");
534*3fe5961aSDevin Teske
535*3fe5961aSDevin Teskeif (bsdconf_put(set, bsdconf_format_path(myfmt),
536*3fe5961aSDevin Teske    bsdconf_format_processing(myfmt),
537*3fe5961aSDevin Teske    bsdconf_format_put(myfmt)) != 0)
538*3fe5961aSDevin Teske	err(1, "%s", bsdconf_format_path(myfmt));
539*3fe5961aSDevin Teske.Ed
540*3fe5961aSDevin Teske.Pp
541*3fe5961aSDevin TeskePromoting such a format into the library itself
542*3fe5961aSDevin Teske.Pq a compiled-in sibling of the built-ins
543*3fe5961aSDevin Teskeis the same data expressed as a translation unit;
544*3fe5961aSDevin Teskesee
545*3fe5961aSDevin Teske.Sx ADDING FORMATS .
546*3fe5961aSDevin Teske.Sh SEE ALSO
547*3fe5961aSDevin Teske.Xr bsdconf 3 ,
548*3fe5961aSDevin Teske.Xr bsdconf_put 3 ,
549*3fe5961aSDevin Teske.Xr loader.conf 5 ,
550*3fe5961aSDevin Teske.Xr src.conf 5 ,
551*3fe5961aSDevin Teske.Xr sysctl.conf 5 ,
552*3fe5961aSDevin Teske.Xr sysconf 8
553*3fe5961aSDevin Teske.Sh HISTORY
554*3fe5961aSDevin TeskeThe format descriptor interface first appeared in
555*3fe5961aSDevin Teske.Fx 16.0
556*3fe5961aSDevin Teskeas part of
557*3fe5961aSDevin Teske.Xr bsdconf 3 .
558*3fe5961aSDevin Teske.Sh AUTHORS
559*3fe5961aSDevin Teske.An Devin Teske Aq Mt dteske@FreeBSD.org
560*3fe5961aSDevin Teske.An Faraz Vahedi Aq Mt kfv@FreeBSD.org
561