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