177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
377cb4d3eSLandon J. Fuller * All rights reserved.
477cb4d3eSLandon J. Fuller *
577cb4d3eSLandon J. Fuller * Redistribution and use in source and binary forms, with or without
677cb4d3eSLandon J. Fuller * modification, are permitted provided that the following conditions
777cb4d3eSLandon J. Fuller * are met:
877cb4d3eSLandon J. Fuller * 1. Redistributions of source code must retain the above copyright
977cb4d3eSLandon J. Fuller * notice, this list of conditions and the following disclaimer,
1077cb4d3eSLandon J. Fuller * without modification.
1177cb4d3eSLandon J. Fuller * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1277cb4d3eSLandon J. Fuller * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1377cb4d3eSLandon J. Fuller * redistribution must be conditioned upon including a substantially
1477cb4d3eSLandon J. Fuller * similar Disclaimer requirement for further binary redistribution.
1577cb4d3eSLandon J. Fuller *
1677cb4d3eSLandon J. Fuller * NO WARRANTY
1777cb4d3eSLandon J. Fuller * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1877cb4d3eSLandon J. Fuller * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1977cb4d3eSLandon J. Fuller * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2077cb4d3eSLandon J. Fuller * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2177cb4d3eSLandon J. Fuller * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2277cb4d3eSLandon J. Fuller * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377cb4d3eSLandon J. Fuller * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477cb4d3eSLandon J. Fuller * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2577cb4d3eSLandon J. Fuller * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677cb4d3eSLandon J. Fuller * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2777cb4d3eSLandon J. Fuller * THE POSSIBILITY OF SUCH DAMAGES.
2877cb4d3eSLandon J. Fuller */
2977cb4d3eSLandon J. Fuller
3019be09f3SLandon J. Fuller #include <sys/param.h>
3119be09f3SLandon J. Fuller #include <sys/hash.h>
3291898857SMark Johnston #include <sys/limits.h>
3377cb4d3eSLandon J. Fuller #include <sys/queue.h>
3477cb4d3eSLandon J. Fuller
3577cb4d3eSLandon J. Fuller #ifdef _KERNEL
3677cb4d3eSLandon J. Fuller
3719be09f3SLandon J. Fuller #include <sys/ctype.h>
3877cb4d3eSLandon J. Fuller #include <sys/systm.h>
3977cb4d3eSLandon J. Fuller
4019be09f3SLandon J. Fuller #include <machine/_inttypes.h>
4119be09f3SLandon J. Fuller
4277cb4d3eSLandon J. Fuller #else /* !_KERNEL */
4377cb4d3eSLandon J. Fuller
4419be09f3SLandon J. Fuller #include <ctype.h>
4577cb4d3eSLandon J. Fuller #include <errno.h>
4619be09f3SLandon J. Fuller #include <inttypes.h>
4777cb4d3eSLandon J. Fuller #include <stdbool.h>
4877cb4d3eSLandon J. Fuller #include <stdio.h>
4977cb4d3eSLandon J. Fuller #include <stdint.h>
5077cb4d3eSLandon J. Fuller #include <stdlib.h>
5177cb4d3eSLandon J. Fuller #include <string.h>
5277cb4d3eSLandon J. Fuller
5377cb4d3eSLandon J. Fuller #endif /* _KERNEL */
5477cb4d3eSLandon J. Fuller
5577cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
5677cb4d3eSLandon J. Fuller #include "bhnd_nvram_datavar.h"
5777cb4d3eSLandon J. Fuller
5877cb4d3eSLandon J. Fuller #include "bhnd_nvram_storevar.h"
5977cb4d3eSLandon J. Fuller
6077cb4d3eSLandon J. Fuller /*
6177cb4d3eSLandon J. Fuller * BHND NVRAM Store
6277cb4d3eSLandon J. Fuller *
6377cb4d3eSLandon J. Fuller * Manages in-memory and persistent representations of NVRAM data.
6477cb4d3eSLandon J. Fuller */
6577cb4d3eSLandon J. Fuller
6619be09f3SLandon J. Fuller static int bhnd_nvstore_parse_data(
6719be09f3SLandon J. Fuller struct bhnd_nvram_store *sc);
6819be09f3SLandon J. Fuller
6919be09f3SLandon J. Fuller static int bhnd_nvstore_parse_path_entries(
7019be09f3SLandon J. Fuller struct bhnd_nvram_store *sc);
7177cb4d3eSLandon J. Fuller
72a7c43ebdSLandon J. Fuller static int bhnd_nvram_store_export_child(
73a7c43ebdSLandon J. Fuller struct bhnd_nvram_store *sc,
74a7c43ebdSLandon J. Fuller bhnd_nvstore_path *top,
75a7c43ebdSLandon J. Fuller bhnd_nvstore_path *child,
76a7c43ebdSLandon J. Fuller bhnd_nvram_plist *plist,
77a7c43ebdSLandon J. Fuller uint32_t flags);
78a7c43ebdSLandon J. Fuller
79a7c43ebdSLandon J. Fuller static int bhnd_nvstore_export_merge(
80a7c43ebdSLandon J. Fuller struct bhnd_nvram_store *sc,
81a7c43ebdSLandon J. Fuller bhnd_nvstore_path *path,
82a7c43ebdSLandon J. Fuller bhnd_nvram_plist *merged,
83a7c43ebdSLandon J. Fuller uint32_t flags);
84a7c43ebdSLandon J. Fuller
85a7c43ebdSLandon J. Fuller static int bhnd_nvstore_export_devpath_alias(
86a7c43ebdSLandon J. Fuller struct bhnd_nvram_store *sc,
87a7c43ebdSLandon J. Fuller bhnd_nvstore_path *path,
88a7c43ebdSLandon J. Fuller const char *devpath,
89a7c43ebdSLandon J. Fuller bhnd_nvram_plist *plist,
90a7c43ebdSLandon J. Fuller u_long *alias_val);
91a7c43ebdSLandon J. Fuller
9277cb4d3eSLandon J. Fuller /**
9377cb4d3eSLandon J. Fuller * Allocate and initialize a new NVRAM data store instance.
9477cb4d3eSLandon J. Fuller *
9577cb4d3eSLandon J. Fuller * The caller is responsible for deallocating the instance via
9677cb4d3eSLandon J. Fuller * bhnd_nvram_store_free().
9777cb4d3eSLandon J. Fuller *
9877cb4d3eSLandon J. Fuller * @param[out] store On success, a pointer to the newly allocated NVRAM data
9977cb4d3eSLandon J. Fuller * instance.
10077cb4d3eSLandon J. Fuller * @param data The NVRAM data to be managed by the returned NVRAM data store
10177cb4d3eSLandon J. Fuller * instance.
10277cb4d3eSLandon J. Fuller *
10377cb4d3eSLandon J. Fuller * @retval 0 success
10477cb4d3eSLandon J. Fuller * @retval non-zero if an error occurs during allocation or initialization, a
10577cb4d3eSLandon J. Fuller * regular unix error code will be returned.
10677cb4d3eSLandon J. Fuller */
10777cb4d3eSLandon J. Fuller int
bhnd_nvram_store_new(struct bhnd_nvram_store ** store,struct bhnd_nvram_data * data)10877cb4d3eSLandon J. Fuller bhnd_nvram_store_new(struct bhnd_nvram_store **store,
10977cb4d3eSLandon J. Fuller struct bhnd_nvram_data *data)
11077cb4d3eSLandon J. Fuller {
11177cb4d3eSLandon J. Fuller struct bhnd_nvram_store *sc;
11277cb4d3eSLandon J. Fuller int error;
11377cb4d3eSLandon J. Fuller
11477cb4d3eSLandon J. Fuller /* Allocate new instance */
11577cb4d3eSLandon J. Fuller sc = bhnd_nv_calloc(1, sizeof(*sc));
11677cb4d3eSLandon J. Fuller if (sc == NULL)
11777cb4d3eSLandon J. Fuller return (ENOMEM);
11877cb4d3eSLandon J. Fuller
11919be09f3SLandon J. Fuller BHND_NVSTORE_LOCK_INIT(sc);
12019be09f3SLandon J. Fuller BHND_NVSTORE_LOCK(sc);
12119be09f3SLandon J. Fuller
12219be09f3SLandon J. Fuller /* Initialize path hash table */
12319be09f3SLandon J. Fuller sc->num_paths = 0;
12419be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->paths); i++)
12519be09f3SLandon J. Fuller LIST_INIT(&sc->paths[i]);
12619be09f3SLandon J. Fuller
12719be09f3SLandon J. Fuller /* Initialize alias hash table */
12819be09f3SLandon J. Fuller sc->num_aliases = 0;
12919be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->aliases); i++)
13019be09f3SLandon J. Fuller LIST_INIT(&sc->aliases[i]);
13177cb4d3eSLandon J. Fuller
13277cb4d3eSLandon J. Fuller /* Retain the NVRAM data */
13319be09f3SLandon J. Fuller sc->data = bhnd_nvram_data_retain(data);
13419be09f3SLandon J. Fuller sc->data_caps = bhnd_nvram_data_caps(data);
135a7c43ebdSLandon J. Fuller sc->data_opts = bhnd_nvram_data_options(data);
136a7c43ebdSLandon J. Fuller if (sc->data_opts != NULL) {
137a7c43ebdSLandon J. Fuller bhnd_nvram_plist_retain(sc->data_opts);
138a7c43ebdSLandon J. Fuller } else {
139a7c43ebdSLandon J. Fuller sc->data_opts = bhnd_nvram_plist_new();
140a7c43ebdSLandon J. Fuller if (sc->data_opts == NULL) {
141a7c43ebdSLandon J. Fuller error = ENOMEM;
142a7c43ebdSLandon J. Fuller goto cleanup;
143a7c43ebdSLandon J. Fuller }
144a7c43ebdSLandon J. Fuller }
14577cb4d3eSLandon J. Fuller
14619be09f3SLandon J. Fuller /* Register required root path */
14719be09f3SLandon J. Fuller error = bhnd_nvstore_register_path(sc, BHND_NVSTORE_ROOT_PATH,
14819be09f3SLandon J. Fuller BHND_NVSTORE_ROOT_PATH_LEN);
14919be09f3SLandon J. Fuller if (error)
15077cb4d3eSLandon J. Fuller goto cleanup;
15177cb4d3eSLandon J. Fuller
15219be09f3SLandon J. Fuller sc->root_path = bhnd_nvstore_get_path(sc, BHND_NVSTORE_ROOT_PATH,
15319be09f3SLandon J. Fuller BHND_NVSTORE_ROOT_PATH_LEN);
15419be09f3SLandon J. Fuller BHND_NV_ASSERT(sc->root_path, ("missing root path"));
15519be09f3SLandon J. Fuller
15619be09f3SLandon J. Fuller /* Parse all variables vended by our backing NVRAM data instance,
15719be09f3SLandon J. Fuller * generating all path entries, alias entries, and variable indexes */
15819be09f3SLandon J. Fuller if ((error = bhnd_nvstore_parse_data(sc)))
15919be09f3SLandon J. Fuller goto cleanup;
16077cb4d3eSLandon J. Fuller
16177cb4d3eSLandon J. Fuller *store = sc;
16219be09f3SLandon J. Fuller
16319be09f3SLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
16477cb4d3eSLandon J. Fuller return (0);
16577cb4d3eSLandon J. Fuller
16677cb4d3eSLandon J. Fuller cleanup:
16719be09f3SLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
16877cb4d3eSLandon J. Fuller bhnd_nvram_store_free(sc);
16977cb4d3eSLandon J. Fuller return (error);
17077cb4d3eSLandon J. Fuller }
17177cb4d3eSLandon J. Fuller
17277cb4d3eSLandon J. Fuller /**
17377cb4d3eSLandon J. Fuller * Allocate and initialize a new NVRAM data store instance, parsing the
17477cb4d3eSLandon J. Fuller * NVRAM data from @p io.
17577cb4d3eSLandon J. Fuller *
17677cb4d3eSLandon J. Fuller * The caller is responsible for deallocating the instance via
17777cb4d3eSLandon J. Fuller * bhnd_nvram_store_free().
17877cb4d3eSLandon J. Fuller *
17977cb4d3eSLandon J. Fuller * The NVRAM data mapped by @p io will be copied, and @p io may be safely
18077cb4d3eSLandon J. Fuller * deallocated after bhnd_nvram_store_new() returns.
18177cb4d3eSLandon J. Fuller *
18277cb4d3eSLandon J. Fuller * @param[out] store On success, a pointer to the newly allocated NVRAM data
18377cb4d3eSLandon J. Fuller * instance.
18477cb4d3eSLandon J. Fuller * @param io An I/O context mapping the NVRAM data to be copied and parsed.
18577cb4d3eSLandon J. Fuller * @param cls The NVRAM data class to be used when parsing @p io, or NULL
18677cb4d3eSLandon J. Fuller * to perform runtime identification of the appropriate data class.
18777cb4d3eSLandon J. Fuller *
18877cb4d3eSLandon J. Fuller * @retval 0 success
18977cb4d3eSLandon J. Fuller * @retval non-zero if an error occurs during allocation or initialization, a
19077cb4d3eSLandon J. Fuller * regular unix error code will be returned.
19177cb4d3eSLandon J. Fuller */
19277cb4d3eSLandon J. Fuller int
bhnd_nvram_store_parse_new(struct bhnd_nvram_store ** store,struct bhnd_nvram_io * io,bhnd_nvram_data_class * cls)19377cb4d3eSLandon J. Fuller bhnd_nvram_store_parse_new(struct bhnd_nvram_store **store,
19458efe686SLandon J. Fuller struct bhnd_nvram_io *io, bhnd_nvram_data_class *cls)
19577cb4d3eSLandon J. Fuller {
19677cb4d3eSLandon J. Fuller struct bhnd_nvram_data *data;
19777cb4d3eSLandon J. Fuller int error;
19877cb4d3eSLandon J. Fuller
19977cb4d3eSLandon J. Fuller /* Try to parse the data */
20077cb4d3eSLandon J. Fuller if ((error = bhnd_nvram_data_new(cls, &data, io)))
20177cb4d3eSLandon J. Fuller return (error);
20277cb4d3eSLandon J. Fuller
20377cb4d3eSLandon J. Fuller /* Try to create our new store instance */
20477cb4d3eSLandon J. Fuller error = bhnd_nvram_store_new(store, data);
20577cb4d3eSLandon J. Fuller bhnd_nvram_data_release(data);
20677cb4d3eSLandon J. Fuller
20777cb4d3eSLandon J. Fuller return (error);
20877cb4d3eSLandon J. Fuller }
20977cb4d3eSLandon J. Fuller
21077cb4d3eSLandon J. Fuller /**
21177cb4d3eSLandon J. Fuller * Free an NVRAM store instance, releasing all associated resources.
21277cb4d3eSLandon J. Fuller *
21377cb4d3eSLandon J. Fuller * @param sc A store instance previously allocated via
21477cb4d3eSLandon J. Fuller * bhnd_nvram_store_new().
21577cb4d3eSLandon J. Fuller */
21677cb4d3eSLandon J. Fuller void
bhnd_nvram_store_free(struct bhnd_nvram_store * sc)21777cb4d3eSLandon J. Fuller bhnd_nvram_store_free(struct bhnd_nvram_store *sc)
21877cb4d3eSLandon J. Fuller {
21977cb4d3eSLandon J. Fuller
22019be09f3SLandon J. Fuller /* Clean up alias hash table */
22119be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->aliases); i++) {
22219be09f3SLandon J. Fuller bhnd_nvstore_alias *alias, *anext;
22319be09f3SLandon J. Fuller LIST_FOREACH_SAFE(alias, &sc->aliases[i], na_link, anext)
22419be09f3SLandon J. Fuller bhnd_nv_free(alias);
22577cb4d3eSLandon J. Fuller }
22677cb4d3eSLandon J. Fuller
22719be09f3SLandon J. Fuller /* Clean up path hash table */
22819be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->paths); i++) {
22919be09f3SLandon J. Fuller bhnd_nvstore_path *path, *pnext;
23019be09f3SLandon J. Fuller LIST_FOREACH_SAFE(path, &sc->paths[i], np_link, pnext)
23119be09f3SLandon J. Fuller bhnd_nvstore_path_free(path);
23219be09f3SLandon J. Fuller }
23377cb4d3eSLandon J. Fuller
23419be09f3SLandon J. Fuller if (sc->data != NULL)
23519be09f3SLandon J. Fuller bhnd_nvram_data_release(sc->data);
23677cb4d3eSLandon J. Fuller
237a7c43ebdSLandon J. Fuller if (sc->data_opts != NULL)
238a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(sc->data_opts);
23977cb4d3eSLandon J. Fuller
24077cb4d3eSLandon J. Fuller BHND_NVSTORE_LOCK_DESTROY(sc);
24177cb4d3eSLandon J. Fuller bhnd_nv_free(sc);
24277cb4d3eSLandon J. Fuller }
24377cb4d3eSLandon J. Fuller
24477cb4d3eSLandon J. Fuller /**
24519be09f3SLandon J. Fuller * Parse all variables vended by our backing NVRAM data instance,
24619be09f3SLandon J. Fuller * generating all path entries, alias entries, and variable indexes.
24719be09f3SLandon J. Fuller *
24819be09f3SLandon J. Fuller * @param sc The NVRAM store instance to be initialized with
24919be09f3SLandon J. Fuller * paths, aliases, and data parsed from its backing
25019be09f3SLandon J. Fuller * data.
25119be09f3SLandon J. Fuller *
25219be09f3SLandon J. Fuller * @retval 0 success
25319be09f3SLandon J. Fuller * @retval non-zero if an error occurs during parsing, a regular unix error
25419be09f3SLandon J. Fuller * code will be returned.
25519be09f3SLandon J. Fuller */
25619be09f3SLandon J. Fuller static int
bhnd_nvstore_parse_data(struct bhnd_nvram_store * sc)25719be09f3SLandon J. Fuller bhnd_nvstore_parse_data(struct bhnd_nvram_store *sc)
25819be09f3SLandon J. Fuller {
25919be09f3SLandon J. Fuller const char *name;
26019be09f3SLandon J. Fuller void *cookiep;
26119be09f3SLandon J. Fuller int error;
26219be09f3SLandon J. Fuller
26319be09f3SLandon J. Fuller /* Parse and register all device paths and path aliases. This enables
26419be09f3SLandon J. Fuller * resolution of _forward_ references to device paths aliases when
26519be09f3SLandon J. Fuller * scanning variable entries below */
26619be09f3SLandon J. Fuller if ((error = bhnd_nvstore_parse_path_entries(sc)))
26719be09f3SLandon J. Fuller return (error);
26819be09f3SLandon J. Fuller
26919be09f3SLandon J. Fuller /* Calculate the per-path variable counts, and report dangling alias
27019be09f3SLandon J. Fuller * references as an error. */
27119be09f3SLandon J. Fuller cookiep = NULL;
27219be09f3SLandon J. Fuller while ((name = bhnd_nvram_data_next(sc->data, &cookiep))) {
27319be09f3SLandon J. Fuller bhnd_nvstore_path *path;
27419be09f3SLandon J. Fuller bhnd_nvstore_name_info info;
27519be09f3SLandon J. Fuller
27619be09f3SLandon J. Fuller /* Parse the name info */
27719be09f3SLandon J. Fuller error = bhnd_nvstore_parse_name_info(name,
27819be09f3SLandon J. Fuller BHND_NVSTORE_NAME_INTERNAL, sc->data_caps, &info);
27919be09f3SLandon J. Fuller if (error)
28019be09f3SLandon J. Fuller return (error);
28119be09f3SLandon J. Fuller
28219be09f3SLandon J. Fuller switch (info.type) {
28319be09f3SLandon J. Fuller case BHND_NVSTORE_VAR:
28419be09f3SLandon J. Fuller /* Fetch referenced path */
28519be09f3SLandon J. Fuller path = bhnd_nvstore_var_get_path(sc, &info);
28619be09f3SLandon J. Fuller if (path == NULL) {
28719be09f3SLandon J. Fuller BHND_NV_LOG("variable '%s' has dangling "
28819be09f3SLandon J. Fuller "path reference\n", name);
28919be09f3SLandon J. Fuller return (EFTYPE);
29019be09f3SLandon J. Fuller }
29119be09f3SLandon J. Fuller
29219be09f3SLandon J. Fuller /* Increment path variable count */
29319be09f3SLandon J. Fuller if (path->num_vars == SIZE_MAX) {
29419be09f3SLandon J. Fuller BHND_NV_LOG("more than SIZE_MAX variables in "
29519be09f3SLandon J. Fuller "path %s\n", path->path_str);
29619be09f3SLandon J. Fuller return (EFTYPE);
29719be09f3SLandon J. Fuller }
29819be09f3SLandon J. Fuller path->num_vars++;
29919be09f3SLandon J. Fuller break;
30019be09f3SLandon J. Fuller
30119be09f3SLandon J. Fuller case BHND_NVSTORE_ALIAS_DECL:
30219be09f3SLandon J. Fuller /* Skip -- path alias already parsed and recorded */
30319be09f3SLandon J. Fuller break;
30419be09f3SLandon J. Fuller }
30519be09f3SLandon J. Fuller }
30619be09f3SLandon J. Fuller
30719be09f3SLandon J. Fuller /* If the backing NVRAM data instance vends only a single root ("/")
30819be09f3SLandon J. Fuller * path, we may be able to skip generating an index for the root
30919be09f3SLandon J. Fuller * path */
31019be09f3SLandon J. Fuller if (sc->num_paths == 1) {
31119be09f3SLandon J. Fuller bhnd_nvstore_path *path;
31219be09f3SLandon J. Fuller
31319be09f3SLandon J. Fuller /* If the backing instance provides its own name-based lookup
31419be09f3SLandon J. Fuller * indexing, we can skip generating a duplicate here */
31519be09f3SLandon J. Fuller if (sc->data_caps & BHND_NVRAM_DATA_CAP_INDEXED)
31619be09f3SLandon J. Fuller return (0);
31719be09f3SLandon J. Fuller
31819be09f3SLandon J. Fuller /* If the sole root path contains fewer variables than the
31919be09f3SLandon J. Fuller * minimum indexing threshhold, we do not need to generate an
32019be09f3SLandon J. Fuller * index */
32119be09f3SLandon J. Fuller path = bhnd_nvstore_get_root_path(sc);
32219be09f3SLandon J. Fuller if (path->num_vars < BHND_NV_IDX_VAR_THRESHOLD)
32319be09f3SLandon J. Fuller return (0);
32419be09f3SLandon J. Fuller }
32519be09f3SLandon J. Fuller
32619be09f3SLandon J. Fuller /* Allocate per-path index instances */
32719be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->paths); i++) {
32819be09f3SLandon J. Fuller bhnd_nvstore_path *path;
32919be09f3SLandon J. Fuller
33019be09f3SLandon J. Fuller LIST_FOREACH(path, &sc->paths[i], np_link) {
33119be09f3SLandon J. Fuller path->index = bhnd_nvstore_index_new(path->num_vars);
33219be09f3SLandon J. Fuller if (path->index == NULL)
33319be09f3SLandon J. Fuller return (ENOMEM);
33419be09f3SLandon J. Fuller }
33519be09f3SLandon J. Fuller }
33619be09f3SLandon J. Fuller
33719be09f3SLandon J. Fuller /* Populate per-path indexes */
33819be09f3SLandon J. Fuller cookiep = NULL;
33919be09f3SLandon J. Fuller while ((name = bhnd_nvram_data_next(sc->data, &cookiep))) {
34019be09f3SLandon J. Fuller bhnd_nvstore_name_info info;
34119be09f3SLandon J. Fuller bhnd_nvstore_path *path;
34219be09f3SLandon J. Fuller
34319be09f3SLandon J. Fuller /* Parse the name info */
34419be09f3SLandon J. Fuller error = bhnd_nvstore_parse_name_info(name,
34519be09f3SLandon J. Fuller BHND_NVSTORE_NAME_INTERNAL, sc->data_caps, &info);
34619be09f3SLandon J. Fuller if (error)
34719be09f3SLandon J. Fuller return (error);
34819be09f3SLandon J. Fuller
34919be09f3SLandon J. Fuller switch (info.type) {
35019be09f3SLandon J. Fuller case BHND_NVSTORE_VAR:
35119be09f3SLandon J. Fuller /* Fetch referenced path */
35219be09f3SLandon J. Fuller path = bhnd_nvstore_var_get_path(sc, &info);
35319be09f3SLandon J. Fuller BHND_NV_ASSERT(path != NULL,
35419be09f3SLandon J. Fuller ("dangling path reference"));
35519be09f3SLandon J. Fuller
35619be09f3SLandon J. Fuller /* Append to index */
35719be09f3SLandon J. Fuller error = bhnd_nvstore_index_append(sc, path->index,
35819be09f3SLandon J. Fuller cookiep);
35919be09f3SLandon J. Fuller if (error)
36019be09f3SLandon J. Fuller return (error);
36119be09f3SLandon J. Fuller break;
36219be09f3SLandon J. Fuller
36319be09f3SLandon J. Fuller case BHND_NVSTORE_ALIAS_DECL:
36419be09f3SLandon J. Fuller /* Skip */
36519be09f3SLandon J. Fuller break;
36619be09f3SLandon J. Fuller }
36719be09f3SLandon J. Fuller }
36819be09f3SLandon J. Fuller
36919be09f3SLandon J. Fuller /* Prepare indexes for querying */
37019be09f3SLandon J. Fuller for (size_t i = 0; i < nitems(sc->paths); i++) {
37119be09f3SLandon J. Fuller bhnd_nvstore_path *path;
37219be09f3SLandon J. Fuller
37319be09f3SLandon J. Fuller LIST_FOREACH(path, &sc->paths[i], np_link) {
37419be09f3SLandon J. Fuller error = bhnd_nvstore_index_prepare(sc, path->index);
37519be09f3SLandon J. Fuller if (error)
37619be09f3SLandon J. Fuller return (error);
37719be09f3SLandon J. Fuller }
37819be09f3SLandon J. Fuller }
37919be09f3SLandon J. Fuller
38019be09f3SLandon J. Fuller return (0);
38119be09f3SLandon J. Fuller }
38219be09f3SLandon J. Fuller
38319be09f3SLandon J. Fuller /**
38419be09f3SLandon J. Fuller * Parse and register path and path alias entries for all declarations found in
38519be09f3SLandon J. Fuller * the NVRAM data backing @p nvram.
38619be09f3SLandon J. Fuller *
38719be09f3SLandon J. Fuller * @param sc The NVRAM store instance.
38819be09f3SLandon J. Fuller *
38919be09f3SLandon J. Fuller * @retval 0 success
39019be09f3SLandon J. Fuller * @retval non-zero If parsing fails, a regular unix error code will be
39119be09f3SLandon J. Fuller * returned.
39219be09f3SLandon J. Fuller */
39319be09f3SLandon J. Fuller static int
bhnd_nvstore_parse_path_entries(struct bhnd_nvram_store * sc)39419be09f3SLandon J. Fuller bhnd_nvstore_parse_path_entries(struct bhnd_nvram_store *sc)
39519be09f3SLandon J. Fuller {
39619be09f3SLandon J. Fuller const char *name;
39719be09f3SLandon J. Fuller void *cookiep;
39819be09f3SLandon J. Fuller int error;
39919be09f3SLandon J. Fuller
40019be09f3SLandon J. Fuller BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
40119be09f3SLandon J. Fuller
40219be09f3SLandon J. Fuller /* Skip path registration if the data source does not support device
40319be09f3SLandon J. Fuller * paths. */
40419be09f3SLandon J. Fuller if (!(sc->data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS)) {
40519be09f3SLandon J. Fuller BHND_NV_ASSERT(sc->root_path != NULL, ("missing root path"));
40619be09f3SLandon J. Fuller return (0);
40719be09f3SLandon J. Fuller }
40819be09f3SLandon J. Fuller
40919be09f3SLandon J. Fuller /* Otherwise, parse and register all paths and path aliases */
41019be09f3SLandon J. Fuller cookiep = NULL;
41119be09f3SLandon J. Fuller while ((name = bhnd_nvram_data_next(sc->data, &cookiep))) {
41219be09f3SLandon J. Fuller bhnd_nvstore_name_info info;
41319be09f3SLandon J. Fuller
41419be09f3SLandon J. Fuller /* Parse the name info */
41519be09f3SLandon J. Fuller error = bhnd_nvstore_parse_name_info(name,
41619be09f3SLandon J. Fuller BHND_NVSTORE_NAME_INTERNAL, sc->data_caps, &info);
41719be09f3SLandon J. Fuller if (error)
41819be09f3SLandon J. Fuller return (error);
41919be09f3SLandon J. Fuller
42019be09f3SLandon J. Fuller /* Register the path */
42119be09f3SLandon J. Fuller error = bhnd_nvstore_var_register_path(sc, &info, cookiep);
42219be09f3SLandon J. Fuller if (error) {
42319be09f3SLandon J. Fuller BHND_NV_LOG("failed to register path for %s: %d\n",
42419be09f3SLandon J. Fuller name, error);
42519be09f3SLandon J. Fuller return (error);
42619be09f3SLandon J. Fuller }
42719be09f3SLandon J. Fuller }
42819be09f3SLandon J. Fuller
42919be09f3SLandon J. Fuller return (0);
43019be09f3SLandon J. Fuller }
431a7c43ebdSLandon J. Fuller
432a7c43ebdSLandon J. Fuller /**
433a7c43ebdSLandon J. Fuller * Merge exported per-path variables (uncommitted, committed, or both) into
434a7c43ebdSLandon J. Fuller * the empty @p merged property list.
435a7c43ebdSLandon J. Fuller *
436a7c43ebdSLandon J. Fuller * @param sc The NVRAM store instance.
437a7c43ebdSLandon J. Fuller * @param path The NVRAM path to be exported.
438a7c43ebdSLandon J. Fuller * @param merged The property list to populate with the merged results.
439a7c43ebdSLandon J. Fuller * @param flags Export flags. See BHND_NVSTORE_EXPORT_*.
440a7c43ebdSLandon J. Fuller *
441a7c43ebdSLandon J. Fuller * @retval 0 success
442a7c43ebdSLandon J. Fuller * @retval ENOMEM If allocation fails.
443a7c43ebdSLandon J. Fuller * @retval non-zero If merging the variables defined in @p path otherwise
444a7c43ebdSLandon J. Fuller * fails, a regular unix error code will be returned.
445a7c43ebdSLandon J. Fuller */
446a7c43ebdSLandon J. Fuller static int
bhnd_nvstore_export_merge(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,bhnd_nvram_plist * merged,uint32_t flags)447a7c43ebdSLandon J. Fuller bhnd_nvstore_export_merge(struct bhnd_nvram_store *sc,
448a7c43ebdSLandon J. Fuller bhnd_nvstore_path *path, bhnd_nvram_plist *merged, uint32_t flags)
449a7c43ebdSLandon J. Fuller {
450a7c43ebdSLandon J. Fuller void *cookiep, *idxp;
451a7c43ebdSLandon J. Fuller int error;
452a7c43ebdSLandon J. Fuller
453a7c43ebdSLandon J. Fuller /* Populate merged list with all pending variables */
454a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_UNCOMMITTED)) {
455a7c43ebdSLandon J. Fuller bhnd_nvram_prop *prop;
456a7c43ebdSLandon J. Fuller
457a7c43ebdSLandon J. Fuller prop = NULL;
458a7c43ebdSLandon J. Fuller while ((prop = bhnd_nvram_plist_next(path->pending, prop))) {
459a7c43ebdSLandon J. Fuller /* Skip variables marked for deletion */
460a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_DELETED)) {
461a7c43ebdSLandon J. Fuller if (bhnd_nvram_prop_is_null(prop))
462a7c43ebdSLandon J. Fuller continue;
463a7c43ebdSLandon J. Fuller }
464a7c43ebdSLandon J. Fuller
465a7c43ebdSLandon J. Fuller /* Append to merged list */
466a7c43ebdSLandon J. Fuller error = bhnd_nvram_plist_append(merged, prop);
467a7c43ebdSLandon J. Fuller if (error)
468a7c43ebdSLandon J. Fuller return (error);
469a7c43ebdSLandon J. Fuller }
470a7c43ebdSLandon J. Fuller }
471a7c43ebdSLandon J. Fuller
472a7c43ebdSLandon J. Fuller /* Skip merging committed variables? */
473a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_COMMITTED))
474a7c43ebdSLandon J. Fuller return (0);
475a7c43ebdSLandon J. Fuller
476a7c43ebdSLandon J. Fuller /* Merge in the committed NVRAM variables */
477a7c43ebdSLandon J. Fuller idxp = NULL;
478a7c43ebdSLandon J. Fuller while ((cookiep = bhnd_nvstore_path_data_next(sc, path, &idxp))) {
479a7c43ebdSLandon J. Fuller const char *name;
480a7c43ebdSLandon J. Fuller bhnd_nvram_val *val;
481a7c43ebdSLandon J. Fuller
482a7c43ebdSLandon J. Fuller /* Fetch the variable name */
483a7c43ebdSLandon J. Fuller name = bhnd_nvram_data_getvar_name(sc->data, cookiep);
484a7c43ebdSLandon J. Fuller
485a7c43ebdSLandon J. Fuller /* Trim device path prefix */
486a7c43ebdSLandon J. Fuller if (sc->data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS)
487a7c43ebdSLandon J. Fuller name = bhnd_nvram_trim_path_name(name);
488a7c43ebdSLandon J. Fuller
489a7c43ebdSLandon J. Fuller /* Skip if already defined in pending updates */
490a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_UNCOMMITTED)) {
491a7c43ebdSLandon J. Fuller if (bhnd_nvram_plist_contains(path->pending, name))
492a7c43ebdSLandon J. Fuller continue;
493a7c43ebdSLandon J. Fuller }
494a7c43ebdSLandon J. Fuller
495a7c43ebdSLandon J. Fuller /* Skip if higher precedence value was already defined. This
496a7c43ebdSLandon J. Fuller * may occur if the underlying data store contains duplicate
497a7c43ebdSLandon J. Fuller * keys; iteration will always return the definition with
498a7c43ebdSLandon J. Fuller * the highest precedence first */
499a7c43ebdSLandon J. Fuller if (bhnd_nvram_plist_contains(merged, name))
500a7c43ebdSLandon J. Fuller continue;
501a7c43ebdSLandon J. Fuller
502a7c43ebdSLandon J. Fuller /* Fetch the variable's value representation */
503a7c43ebdSLandon J. Fuller if ((error = bhnd_nvram_data_copy_val(sc->data, cookiep, &val)))
504a7c43ebdSLandon J. Fuller return (error);
505a7c43ebdSLandon J. Fuller
506a7c43ebdSLandon J. Fuller /* Add to path variable list */
507a7c43ebdSLandon J. Fuller error = bhnd_nvram_plist_append_val(merged, name, val);
508a7c43ebdSLandon J. Fuller bhnd_nvram_val_release(val);
509a7c43ebdSLandon J. Fuller if (error)
510a7c43ebdSLandon J. Fuller return (error);
511a7c43ebdSLandon J. Fuller }
512a7c43ebdSLandon J. Fuller
513a7c43ebdSLandon J. Fuller return (0);
514a7c43ebdSLandon J. Fuller }
515a7c43ebdSLandon J. Fuller
516a7c43ebdSLandon J. Fuller /**
517a7c43ebdSLandon J. Fuller * Find a free alias value for @p path, and append the devpathXX alias
518a7c43ebdSLandon J. Fuller * declaration to @p plist.
519a7c43ebdSLandon J. Fuller *
520a7c43ebdSLandon J. Fuller * @param sc The NVRAM store instance.
521a7c43ebdSLandon J. Fuller * @param path The NVRAM path for which a devpath alias
522a7c43ebdSLandon J. Fuller * variable should be produced.
523a7c43ebdSLandon J. Fuller * @param devpath The devpathXX path value for @p path.
524a7c43ebdSLandon J. Fuller * @param plist The property list to which @p path's devpath
525a7c43ebdSLandon J. Fuller * variable will be appended.
526a7c43ebdSLandon J. Fuller * @param[out] alias_val On success, will be set to the alias value
527a7c43ebdSLandon J. Fuller * allocated for @p path.
528a7c43ebdSLandon J. Fuller *
529a7c43ebdSLandon J. Fuller * @retval 0 success
530a7c43ebdSLandon J. Fuller * @retval ENOMEM If allocation fails.
531a7c43ebdSLandon J. Fuller * @retval non-zero If merging the variables defined in @p path otherwise
532a7c43ebdSLandon J. Fuller * fails, a regular unix error code will be returned.
533a7c43ebdSLandon J. Fuller */
534a7c43ebdSLandon J. Fuller static int
bhnd_nvstore_export_devpath_alias(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,const char * devpath,bhnd_nvram_plist * plist,u_long * alias_val)535a7c43ebdSLandon J. Fuller bhnd_nvstore_export_devpath_alias(struct bhnd_nvram_store *sc,
536a7c43ebdSLandon J. Fuller bhnd_nvstore_path *path, const char *devpath, bhnd_nvram_plist *plist,
537a7c43ebdSLandon J. Fuller u_long *alias_val)
538a7c43ebdSLandon J. Fuller {
539a7c43ebdSLandon J. Fuller bhnd_nvstore_alias *alias;
540a7c43ebdSLandon J. Fuller char *pathvar;
541a7c43ebdSLandon J. Fuller int error;
542a7c43ebdSLandon J. Fuller
543a7c43ebdSLandon J. Fuller *alias_val = 0;
544a7c43ebdSLandon J. Fuller
545a7c43ebdSLandon J. Fuller /* Prefer alias value already reserved for this path. */
546a7c43ebdSLandon J. Fuller alias = bhnd_nvstore_find_alias(sc, path->path_str);
547a7c43ebdSLandon J. Fuller if (alias != NULL) {
548a7c43ebdSLandon J. Fuller *alias_val = alias->alias;
549a7c43ebdSLandon J. Fuller
550a7c43ebdSLandon J. Fuller /* Allocate devpathXX variable name */
551a7c43ebdSLandon J. Fuller bhnd_nv_asprintf(&pathvar, "devpath%lu", *alias_val);
552a7c43ebdSLandon J. Fuller if (pathvar == NULL)
553a7c43ebdSLandon J. Fuller return (ENOMEM);
554a7c43ebdSLandon J. Fuller
555a7c43ebdSLandon J. Fuller /* Append alias variable to property list */
556a7c43ebdSLandon J. Fuller error = bhnd_nvram_plist_append_string(plist, pathvar, devpath);
557a7c43ebdSLandon J. Fuller
558a7c43ebdSLandon J. Fuller BHND_NV_ASSERT(error != EEXIST, ("reserved alias %lu:%s in use",
559a7c43ebdSLandon J. Fuller * alias_val, path->path_str));
560a7c43ebdSLandon J. Fuller
561a7c43ebdSLandon J. Fuller bhnd_nv_free(pathvar);
562a7c43ebdSLandon J. Fuller return (error);
563a7c43ebdSLandon J. Fuller }
564a7c43ebdSLandon J. Fuller
565a7c43ebdSLandon J. Fuller /* Find the next free devpathXX alias entry */
566a7c43ebdSLandon J. Fuller while (1) {
567a7c43ebdSLandon J. Fuller /* Skip existing reserved alias values */
568a7c43ebdSLandon J. Fuller while (bhnd_nvstore_get_alias(sc, *alias_val) != NULL) {
569a7c43ebdSLandon J. Fuller if (*alias_val == ULONG_MAX)
570a7c43ebdSLandon J. Fuller return (ENOMEM);
571a7c43ebdSLandon J. Fuller
572a7c43ebdSLandon J. Fuller (*alias_val)++;
573a7c43ebdSLandon J. Fuller }
574a7c43ebdSLandon J. Fuller
575a7c43ebdSLandon J. Fuller /* Allocate devpathXX variable name */
576a7c43ebdSLandon J. Fuller bhnd_nv_asprintf(&pathvar, "devpath%lu", *alias_val);
577a7c43ebdSLandon J. Fuller if (pathvar == NULL)
578a7c43ebdSLandon J. Fuller return (ENOMEM);
579a7c43ebdSLandon J. Fuller
580a7c43ebdSLandon J. Fuller /* If not in-use, we can terminate the search */
581a7c43ebdSLandon J. Fuller if (!bhnd_nvram_plist_contains(plist, pathvar))
582a7c43ebdSLandon J. Fuller break;
583a7c43ebdSLandon J. Fuller
584a7c43ebdSLandon J. Fuller /* Keep searching */
585a7c43ebdSLandon J. Fuller bhnd_nv_free(pathvar);
586a7c43ebdSLandon J. Fuller
587a7c43ebdSLandon J. Fuller if (*alias_val == ULONG_MAX)
588a7c43ebdSLandon J. Fuller return (ENOMEM);
589a7c43ebdSLandon J. Fuller
590a7c43ebdSLandon J. Fuller (*alias_val)++;
591a7c43ebdSLandon J. Fuller }
592a7c43ebdSLandon J. Fuller
593a7c43ebdSLandon J. Fuller /* Append alias variable to property list */
594a7c43ebdSLandon J. Fuller error = bhnd_nvram_plist_append_string(plist, pathvar, devpath);
595a7c43ebdSLandon J. Fuller
596a7c43ebdSLandon J. Fuller bhnd_nv_free(pathvar);
597a7c43ebdSLandon J. Fuller return (error);
598a7c43ebdSLandon J. Fuller }
599a7c43ebdSLandon J. Fuller
600a7c43ebdSLandon J. Fuller /**
601a7c43ebdSLandon J. Fuller * Export a single @p child path's properties, appending the result to @p plist.
602a7c43ebdSLandon J. Fuller *
603a7c43ebdSLandon J. Fuller * @param sc The NVRAM store instance.
604a7c43ebdSLandon J. Fuller * @param top The root NVRAM path being exported.
605a7c43ebdSLandon J. Fuller * @param child The NVRAM path to be exported.
606a7c43ebdSLandon J. Fuller * @param plist The property list to which @p child's exported
607a7c43ebdSLandon J. Fuller * properties should be appended.
608a7c43ebdSLandon J. Fuller * @param flags Export flags. See BHND_NVSTORE_EXPORT_*.
609a7c43ebdSLandon J. Fuller *
610a7c43ebdSLandon J. Fuller * @retval 0 success
611a7c43ebdSLandon J. Fuller * @retval ENOMEM If allocation fails.
612a7c43ebdSLandon J. Fuller * @retval non-zero If merging the variables defined in @p path otherwise
613a7c43ebdSLandon J. Fuller * fails, a regular unix error code will be returned.
614a7c43ebdSLandon J. Fuller */
615a7c43ebdSLandon J. Fuller static int
bhnd_nvram_store_export_child(struct bhnd_nvram_store * sc,bhnd_nvstore_path * top,bhnd_nvstore_path * child,bhnd_nvram_plist * plist,uint32_t flags)616a7c43ebdSLandon J. Fuller bhnd_nvram_store_export_child(struct bhnd_nvram_store *sc,
617a7c43ebdSLandon J. Fuller bhnd_nvstore_path *top, bhnd_nvstore_path *child, bhnd_nvram_plist *plist,
618a7c43ebdSLandon J. Fuller uint32_t flags)
619a7c43ebdSLandon J. Fuller {
620a7c43ebdSLandon J. Fuller bhnd_nvram_plist *path_vars;
621a7c43ebdSLandon J. Fuller bhnd_nvram_prop *prop;
622a7c43ebdSLandon J. Fuller const char *relpath;
623a7c43ebdSLandon J. Fuller char *prefix, *namebuf;
624a7c43ebdSLandon J. Fuller size_t prefix_len, relpath_len;
625*87a43286SWarner Losh size_t namebuf_size;
626a7c43ebdSLandon J. Fuller bool emit_compact_devpath;
627a7c43ebdSLandon J. Fuller int error;
628a7c43ebdSLandon J. Fuller
629a7c43ebdSLandon J. Fuller BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
630a7c43ebdSLandon J. Fuller
631a7c43ebdSLandon J. Fuller prefix = NULL;
632a7c43ebdSLandon J. Fuller path_vars = NULL;
633a7c43ebdSLandon J. Fuller namebuf = NULL;
634a7c43ebdSLandon J. Fuller
635a7c43ebdSLandon J. Fuller /* Determine the path relative to the top-level path */
636a7c43ebdSLandon J. Fuller relpath = bhnd_nvstore_parse_relpath(top->path_str, child->path_str);
637a7c43ebdSLandon J. Fuller if (relpath == NULL) {
638a7c43ebdSLandon J. Fuller /* Skip -- not a child of the root path */
639a7c43ebdSLandon J. Fuller return (0);
640a7c43ebdSLandon J. Fuller }
641a7c43ebdSLandon J. Fuller relpath_len = strlen(relpath);
642a7c43ebdSLandon J. Fuller
643a7c43ebdSLandon J. Fuller /* Skip sub-path if export of children was not requested, */
644a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_CHILDREN) && relpath_len > 0)
645a7c43ebdSLandon J. Fuller return (0);
646a7c43ebdSLandon J. Fuller
647a7c43ebdSLandon J. Fuller /* Collect all variables to be included in the export */
648a7c43ebdSLandon J. Fuller if ((path_vars = bhnd_nvram_plist_new()) == NULL)
649a7c43ebdSLandon J. Fuller return (ENOMEM);
650a7c43ebdSLandon J. Fuller
651a7c43ebdSLandon J. Fuller if ((error = bhnd_nvstore_export_merge(sc, child, path_vars, flags))) {
652a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(path_vars);
653a7c43ebdSLandon J. Fuller return (error);
654a7c43ebdSLandon J. Fuller }
655a7c43ebdSLandon J. Fuller
656a7c43ebdSLandon J. Fuller /* Skip if no children are to be exported */
657a7c43ebdSLandon J. Fuller if (bhnd_nvram_plist_count(path_vars) == 0) {
658a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(path_vars);
659a7c43ebdSLandon J. Fuller return (0);
660a7c43ebdSLandon J. Fuller }
661a7c43ebdSLandon J. Fuller
662a7c43ebdSLandon J. Fuller /* Determine appropriate device path encoding */
663a7c43ebdSLandon J. Fuller emit_compact_devpath = false;
664a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_COMPACT_DEVPATHS)) {
665a7c43ebdSLandon J. Fuller /* Re-encode as compact (if non-empty path) */
666a7c43ebdSLandon J. Fuller if (relpath_len > 0)
667a7c43ebdSLandon J. Fuller emit_compact_devpath = true;
668a7c43ebdSLandon J. Fuller } else if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_EXPAND_DEVPATHS)) {
669a7c43ebdSLandon J. Fuller /* Re-encode with fully expanded device path */
670a7c43ebdSLandon J. Fuller emit_compact_devpath = false;
671a7c43ebdSLandon J. Fuller } else if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_PRESERVE_DEVPATHS)) {
672a7c43ebdSLandon J. Fuller /* Preserve existing encoding of this path */
673a7c43ebdSLandon J. Fuller if (bhnd_nvstore_find_alias(sc, child->path_str) != NULL)
674a7c43ebdSLandon J. Fuller emit_compact_devpath = true;
675a7c43ebdSLandon J. Fuller } else {
676a7c43ebdSLandon J. Fuller BHND_NV_LOG("invalid device path flag: %#" PRIx32, flags);
677a7c43ebdSLandon J. Fuller error = EINVAL;
678a7c43ebdSLandon J. Fuller goto finished;
679a7c43ebdSLandon J. Fuller }
680a7c43ebdSLandon J. Fuller
681a7c43ebdSLandon J. Fuller /* Allocate variable device path prefix to use for all property names,
682a7c43ebdSLandon J. Fuller * and if using compact encoding, emit the devpathXX= variable */
683a7c43ebdSLandon J. Fuller prefix = NULL;
684a7c43ebdSLandon J. Fuller prefix_len = 0;
685a7c43ebdSLandon J. Fuller if (emit_compact_devpath) {
686a7c43ebdSLandon J. Fuller u_long alias_val;
687a7c43ebdSLandon J. Fuller int len;
688a7c43ebdSLandon J. Fuller
689a7c43ebdSLandon J. Fuller /* Reserve an alias value and append the devpathXX= variable to
690a7c43ebdSLandon J. Fuller * the property list */
691a7c43ebdSLandon J. Fuller error = bhnd_nvstore_export_devpath_alias(sc, child, relpath,
692a7c43ebdSLandon J. Fuller plist, &alias_val);
693a7c43ebdSLandon J. Fuller if (error)
694a7c43ebdSLandon J. Fuller goto finished;
695a7c43ebdSLandon J. Fuller
696a7c43ebdSLandon J. Fuller /* Allocate variable name prefix */
697a7c43ebdSLandon J. Fuller len = bhnd_nv_asprintf(&prefix, "%lu:", alias_val);
698a7c43ebdSLandon J. Fuller if (prefix == NULL) {
699a7c43ebdSLandon J. Fuller error = ENOMEM;
700a7c43ebdSLandon J. Fuller goto finished;
701a7c43ebdSLandon J. Fuller }
702a7c43ebdSLandon J. Fuller
703a7c43ebdSLandon J. Fuller prefix_len = len;
704a7c43ebdSLandon J. Fuller } else if (relpath_len > 0) {
705a7c43ebdSLandon J. Fuller int len;
706a7c43ebdSLandon J. Fuller
707a7c43ebdSLandon J. Fuller /* Allocate the variable name prefix, appending '/' to the
708a7c43ebdSLandon J. Fuller * relative path */
709a7c43ebdSLandon J. Fuller len = bhnd_nv_asprintf(&prefix, "%s/", relpath);
710a7c43ebdSLandon J. Fuller if (prefix == NULL) {
711a7c43ebdSLandon J. Fuller error = ENOMEM;
712a7c43ebdSLandon J. Fuller goto finished;
713a7c43ebdSLandon J. Fuller }
714a7c43ebdSLandon J. Fuller
715a7c43ebdSLandon J. Fuller prefix_len = len;
716a7c43ebdSLandon J. Fuller }
717a7c43ebdSLandon J. Fuller
718a7c43ebdSLandon J. Fuller /* If prefixing of variable names is required, allocate a name
719a7c43ebdSLandon J. Fuller * formatting buffer */
720a7c43ebdSLandon J. Fuller namebuf_size = 0;
721a7c43ebdSLandon J. Fuller if (prefix != NULL) {
722a7c43ebdSLandon J. Fuller size_t maxlen;
723a7c43ebdSLandon J. Fuller
724a7c43ebdSLandon J. Fuller /* Find the maximum name length */
725a7c43ebdSLandon J. Fuller maxlen = 0;
726a7c43ebdSLandon J. Fuller prop = NULL;
727a7c43ebdSLandon J. Fuller while ((prop = bhnd_nvram_plist_next(path_vars, prop))) {
728a7c43ebdSLandon J. Fuller const char *name;
729a7c43ebdSLandon J. Fuller
730a7c43ebdSLandon J. Fuller name = bhnd_nvram_prop_name(prop);
731a7c43ebdSLandon J. Fuller maxlen = bhnd_nv_ummax(strlen(name), maxlen);
732a7c43ebdSLandon J. Fuller }
733a7c43ebdSLandon J. Fuller
734a7c43ebdSLandon J. Fuller /* Allocate name buffer (path-prefix + name + '\0') */
735a7c43ebdSLandon J. Fuller namebuf_size = prefix_len + maxlen + 1;
736a7c43ebdSLandon J. Fuller namebuf = bhnd_nv_malloc(namebuf_size);
737a7c43ebdSLandon J. Fuller if (namebuf == NULL) {
738a7c43ebdSLandon J. Fuller error = ENOMEM;
739a7c43ebdSLandon J. Fuller goto finished;
740a7c43ebdSLandon J. Fuller }
741a7c43ebdSLandon J. Fuller }
742a7c43ebdSLandon J. Fuller
743a7c43ebdSLandon J. Fuller /* Append all path variables to the export plist, prepending the
744a7c43ebdSLandon J. Fuller * device-path prefix to the variable names, if required */
745a7c43ebdSLandon J. Fuller prop = NULL;
746a7c43ebdSLandon J. Fuller while ((prop = bhnd_nvram_plist_next(path_vars, prop)) != NULL) {
747a7c43ebdSLandon J. Fuller const char *name;
748a7c43ebdSLandon J. Fuller
749a7c43ebdSLandon J. Fuller /* Prepend device prefix to the variable name */
750a7c43ebdSLandon J. Fuller name = bhnd_nvram_prop_name(prop);
751a7c43ebdSLandon J. Fuller if (prefix != NULL) {
752a7c43ebdSLandon J. Fuller int len;
753a7c43ebdSLandon J. Fuller
754a7c43ebdSLandon J. Fuller /*
755a7c43ebdSLandon J. Fuller * Write prefixed variable name to our name buffer.
756a7c43ebdSLandon J. Fuller *
757a7c43ebdSLandon J. Fuller * We precalcuate the size when scanning all names
758a7c43ebdSLandon J. Fuller * above, so this should always succeed.
759a7c43ebdSLandon J. Fuller */
760a7c43ebdSLandon J. Fuller len = snprintf(namebuf, namebuf_size, "%s%s", prefix,
761a7c43ebdSLandon J. Fuller name);
762a7c43ebdSLandon J. Fuller if (len < 0 || (size_t)len >= namebuf_size)
763a7c43ebdSLandon J. Fuller BHND_NV_PANIC("invalid max_name_len");
764a7c43ebdSLandon J. Fuller
765a7c43ebdSLandon J. Fuller name = namebuf;
766a7c43ebdSLandon J. Fuller }
767a7c43ebdSLandon J. Fuller
768a7c43ebdSLandon J. Fuller /* Add property to export plist */
769a7c43ebdSLandon J. Fuller error = bhnd_nvram_plist_append_val(plist, name,
770a7c43ebdSLandon J. Fuller bhnd_nvram_prop_val(prop));
771a7c43ebdSLandon J. Fuller if (error)
772a7c43ebdSLandon J. Fuller goto finished;
773a7c43ebdSLandon J. Fuller }
774a7c43ebdSLandon J. Fuller
775a7c43ebdSLandon J. Fuller /* Success */
776a7c43ebdSLandon J. Fuller error = 0;
777a7c43ebdSLandon J. Fuller
778a7c43ebdSLandon J. Fuller finished:
779a7c43ebdSLandon J. Fuller if (prefix != NULL)
780a7c43ebdSLandon J. Fuller bhnd_nv_free(prefix);
781a7c43ebdSLandon J. Fuller
782a7c43ebdSLandon J. Fuller if (namebuf != NULL)
783a7c43ebdSLandon J. Fuller bhnd_nv_free(namebuf);
784a7c43ebdSLandon J. Fuller
785a7c43ebdSLandon J. Fuller if (path_vars != NULL)
786a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(path_vars);
787a7c43ebdSLandon J. Fuller
788a7c43ebdSLandon J. Fuller return (error);
789a7c43ebdSLandon J. Fuller }
790a7c43ebdSLandon J. Fuller
791a7c43ebdSLandon J. Fuller /**
792a7c43ebdSLandon J. Fuller * Export a flat, ordered NVRAM property list representation of all NVRAM
793a7c43ebdSLandon J. Fuller * properties at @p path.
794a7c43ebdSLandon J. Fuller *
795a7c43ebdSLandon J. Fuller * @param sc The NVRAM store instance.
796a7c43ebdSLandon J. Fuller * @param path The NVRAM path to export, or NULL to select the root
797a7c43ebdSLandon J. Fuller * path.
798a7c43ebdSLandon J. Fuller * @param[out] cls On success, will be set to the backing data class
799a7c43ebdSLandon J. Fuller * of @p sc. If the data class is are not desired,
800a7c43ebdSLandon J. Fuller * a NULL pointer may be provided.
801a7c43ebdSLandon J. Fuller * @param[out] props On success, will be set to a caller-owned property
802a7c43ebdSLandon J. Fuller * list containing the exported properties. The caller is
803a7c43ebdSLandon J. Fuller * responsible for releasing this value via
804a7c43ebdSLandon J. Fuller * bhnd_nvram_plist_release().
805a7c43ebdSLandon J. Fuller * @param[out] options On success, will be set to a caller-owned property
806a7c43ebdSLandon J. Fuller * list containing the current NVRAM serialization options
807a7c43ebdSLandon J. Fuller * for @p sc. The caller is responsible for releasing this
808a7c43ebdSLandon J. Fuller * value via bhnd_nvram_plist_release().
809a7c43ebdSLandon J. Fuller * @param flags Export flags. See BHND_NVSTORE_EXPORT_*.
810a7c43ebdSLandon J. Fuller *
811a7c43ebdSLandon J. Fuller * @retval 0 success
812a7c43ebdSLandon J. Fuller * @retval EINVAL If @p flags is invalid.
813a7c43ebdSLandon J. Fuller * @retval ENOENT The requested path was not found.
814a7c43ebdSLandon J. Fuller * @retval ENOMEM If allocation fails.
815a7c43ebdSLandon J. Fuller * @retval non-zero If export of @p path otherwise fails, a regular unix
816a7c43ebdSLandon J. Fuller * error code will be returned.
817a7c43ebdSLandon J. Fuller */
818a7c43ebdSLandon J. Fuller int
bhnd_nvram_store_export(struct bhnd_nvram_store * sc,const char * path,bhnd_nvram_data_class ** cls,bhnd_nvram_plist ** props,bhnd_nvram_plist ** options,uint32_t flags)819a7c43ebdSLandon J. Fuller bhnd_nvram_store_export(struct bhnd_nvram_store *sc, const char *path,
820a7c43ebdSLandon J. Fuller bhnd_nvram_data_class **cls, bhnd_nvram_plist **props,
821a7c43ebdSLandon J. Fuller bhnd_nvram_plist **options, uint32_t flags)
822a7c43ebdSLandon J. Fuller {
823a7c43ebdSLandon J. Fuller bhnd_nvram_plist *unordered;
824a7c43ebdSLandon J. Fuller bhnd_nvstore_path *top;
825a7c43ebdSLandon J. Fuller bhnd_nvram_prop *prop;
826a7c43ebdSLandon J. Fuller const char *name;
827a7c43ebdSLandon J. Fuller void *cookiep;
828a7c43ebdSLandon J. Fuller size_t num_dpath_flags;
829a7c43ebdSLandon J. Fuller int error;
830a7c43ebdSLandon J. Fuller
831a7c43ebdSLandon J. Fuller *props = NULL;
832a7c43ebdSLandon J. Fuller unordered = NULL;
833a7c43ebdSLandon J. Fuller num_dpath_flags = 0;
834a7c43ebdSLandon J. Fuller if (options != NULL)
835a7c43ebdSLandon J. Fuller *options = NULL;
836a7c43ebdSLandon J. Fuller
837a7c43ebdSLandon J. Fuller /* Default to exporting root path */
838a7c43ebdSLandon J. Fuller if (path == NULL)
839a7c43ebdSLandon J. Fuller path = BHND_NVSTORE_ROOT_PATH;
840a7c43ebdSLandon J. Fuller
841a7c43ebdSLandon J. Fuller /* Default to exporting all properties */
842a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_COMMITTED) &&
843a7c43ebdSLandon J. Fuller !BHND_NVSTORE_GET_FLAG(flags, EXPORT_UNCOMMITTED))
844a7c43ebdSLandon J. Fuller {
845a7c43ebdSLandon J. Fuller flags |= BHND_NVSTORE_EXPORT_ALL_VARS;
846a7c43ebdSLandon J. Fuller }
847a7c43ebdSLandon J. Fuller
848a7c43ebdSLandon J. Fuller /* Default to preserving the current device path encoding */
849a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_COMPACT_DEVPATHS) &&
850a7c43ebdSLandon J. Fuller !BHND_NVSTORE_GET_FLAG(flags, EXPORT_EXPAND_DEVPATHS))
851a7c43ebdSLandon J. Fuller {
852a7c43ebdSLandon J. Fuller flags |= BHND_NVSTORE_EXPORT_PRESERVE_DEVPATHS;
853a7c43ebdSLandon J. Fuller }
854a7c43ebdSLandon J. Fuller
855a7c43ebdSLandon J. Fuller /* Exactly one device path encoding flag must be set */
856a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_COMPACT_DEVPATHS))
857a7c43ebdSLandon J. Fuller num_dpath_flags++;
858a7c43ebdSLandon J. Fuller
859a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_EXPAND_DEVPATHS))
860a7c43ebdSLandon J. Fuller num_dpath_flags++;
861a7c43ebdSLandon J. Fuller
862a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_PRESERVE_DEVPATHS))
863a7c43ebdSLandon J. Fuller num_dpath_flags++;
864a7c43ebdSLandon J. Fuller
865a7c43ebdSLandon J. Fuller if (num_dpath_flags != 1)
866a7c43ebdSLandon J. Fuller return (EINVAL);
867a7c43ebdSLandon J. Fuller
868a7c43ebdSLandon J. Fuller /* If EXPORT_DELETED is set, EXPORT_UNCOMMITTED must be set too */
869a7c43ebdSLandon J. Fuller if (BHND_NVSTORE_GET_FLAG(flags, EXPORT_DELETED) &&
870a7c43ebdSLandon J. Fuller !BHND_NVSTORE_GET_FLAG(flags, EXPORT_DELETED))
871a7c43ebdSLandon J. Fuller {
872a7c43ebdSLandon J. Fuller return (EINVAL);
873a7c43ebdSLandon J. Fuller }
874a7c43ebdSLandon J. Fuller
875a7c43ebdSLandon J. Fuller /* Lock internal state before querying paths/properties */
876a7c43ebdSLandon J. Fuller BHND_NVSTORE_LOCK(sc);
877a7c43ebdSLandon J. Fuller
878a7c43ebdSLandon J. Fuller /* Fetch referenced path */
879a7c43ebdSLandon J. Fuller top = bhnd_nvstore_get_path(sc, path, strlen(path));
880a7c43ebdSLandon J. Fuller if (top == NULL) {
881a7c43ebdSLandon J. Fuller error = ENOENT;
882a7c43ebdSLandon J. Fuller goto failed;
883a7c43ebdSLandon J. Fuller }
884a7c43ebdSLandon J. Fuller
885a7c43ebdSLandon J. Fuller /* Allocate new, empty property list */
886a7c43ebdSLandon J. Fuller if ((unordered = bhnd_nvram_plist_new()) == NULL) {
887a7c43ebdSLandon J. Fuller error = ENOMEM;
888a7c43ebdSLandon J. Fuller goto failed;
889a7c43ebdSLandon J. Fuller }
890a7c43ebdSLandon J. Fuller
891a7c43ebdSLandon J. Fuller /* Export the top-level path first */
892a7c43ebdSLandon J. Fuller error = bhnd_nvram_store_export_child(sc, top, top, unordered, flags);
893a7c43ebdSLandon J. Fuller if (error)
894a7c43ebdSLandon J. Fuller goto failed;
895a7c43ebdSLandon J. Fuller
896a7c43ebdSLandon J. Fuller /* Attempt to export any children of the root path */
897a7c43ebdSLandon J. Fuller for (size_t i = 0; i < nitems(sc->paths); i++) {
898a7c43ebdSLandon J. Fuller bhnd_nvstore_path *child;
899a7c43ebdSLandon J. Fuller
900a7c43ebdSLandon J. Fuller LIST_FOREACH(child, &sc->paths[i], np_link) {
901a7c43ebdSLandon J. Fuller /* Top-level path was already exported */
902a7c43ebdSLandon J. Fuller if (child == top)
903a7c43ebdSLandon J. Fuller continue;
904a7c43ebdSLandon J. Fuller
905a7c43ebdSLandon J. Fuller error = bhnd_nvram_store_export_child(sc, top,
906a7c43ebdSLandon J. Fuller child, unordered, flags);
907a7c43ebdSLandon J. Fuller if (error)
908a7c43ebdSLandon J. Fuller goto failed;
909a7c43ebdSLandon J. Fuller }
910a7c43ebdSLandon J. Fuller }
911a7c43ebdSLandon J. Fuller
912a7c43ebdSLandon J. Fuller /* If requested, provide the current class and serialization options */
913a7c43ebdSLandon J. Fuller if (cls != NULL)
914a7c43ebdSLandon J. Fuller *cls = bhnd_nvram_data_get_class(sc->data);
915a7c43ebdSLandon J. Fuller
916a7c43ebdSLandon J. Fuller if (options != NULL)
917a7c43ebdSLandon J. Fuller *options = bhnd_nvram_plist_retain(sc->data_opts);
918a7c43ebdSLandon J. Fuller
919a7c43ebdSLandon J. Fuller /*
920a7c43ebdSLandon J. Fuller * If we're re-encoding device paths, don't bother preserving the
921a7c43ebdSLandon J. Fuller * existing NVRAM variable order; our variable names will not match
922a7c43ebdSLandon J. Fuller * the existing backing NVRAM data.
923a7c43ebdSLandon J. Fuller */
924a7c43ebdSLandon J. Fuller if (!BHND_NVSTORE_GET_FLAG(flags, EXPORT_PRESERVE_DEVPATHS)) {
925a7c43ebdSLandon J. Fuller *props = unordered;
926a7c43ebdSLandon J. Fuller unordered = NULL;
927a7c43ebdSLandon J. Fuller
928a7c43ebdSLandon J. Fuller goto finished;
929a7c43ebdSLandon J. Fuller }
930a7c43ebdSLandon J. Fuller
931a7c43ebdSLandon J. Fuller /*
932a7c43ebdSLandon J. Fuller * Re-order the flattened output to match the existing NVRAM variable
933a7c43ebdSLandon J. Fuller * ordering.
934a7c43ebdSLandon J. Fuller *
935a7c43ebdSLandon J. Fuller * We append all new variables at the end of the input; this should
936a7c43ebdSLandon J. Fuller * reduce the delta that needs to be written (e.g. to flash) when
937a7c43ebdSLandon J. Fuller * committing NVRAM updates, and should result in a serialization
938a7c43ebdSLandon J. Fuller * identical to the input serialization if uncommitted updates are
939a7c43ebdSLandon J. Fuller * excluded from the export.
940a7c43ebdSLandon J. Fuller */
941a7c43ebdSLandon J. Fuller if ((*props = bhnd_nvram_plist_new()) == NULL) {
942a7c43ebdSLandon J. Fuller error = ENOMEM;
943a7c43ebdSLandon J. Fuller goto failed;
944a7c43ebdSLandon J. Fuller }
945a7c43ebdSLandon J. Fuller
946a7c43ebdSLandon J. Fuller /* Using the backing NVRAM data ordering to order all variables
947a7c43ebdSLandon J. Fuller * currently defined in the backing store */
948a7c43ebdSLandon J. Fuller cookiep = NULL;
949a7c43ebdSLandon J. Fuller while ((name = bhnd_nvram_data_next(sc->data, &cookiep))) {
950a7c43ebdSLandon J. Fuller prop = bhnd_nvram_plist_get_prop(unordered, name);
951a7c43ebdSLandon J. Fuller if (prop == NULL)
952a7c43ebdSLandon J. Fuller continue;
953a7c43ebdSLandon J. Fuller
954a7c43ebdSLandon J. Fuller /* Append to ordered result */
955a7c43ebdSLandon J. Fuller if ((error = bhnd_nvram_plist_append(*props, prop)))
956a7c43ebdSLandon J. Fuller goto failed;
957a7c43ebdSLandon J. Fuller
958a7c43ebdSLandon J. Fuller /* Remove from unordered list */
959a7c43ebdSLandon J. Fuller bhnd_nvram_plist_remove(unordered, name);
960a7c43ebdSLandon J. Fuller }
961a7c43ebdSLandon J. Fuller
962a7c43ebdSLandon J. Fuller /* Any remaining variables are new, and should be appended to the
963a7c43ebdSLandon J. Fuller * end of the export list */
964a7c43ebdSLandon J. Fuller prop = NULL;
965a7c43ebdSLandon J. Fuller while ((prop = bhnd_nvram_plist_next(unordered, prop)) != NULL) {
966a7c43ebdSLandon J. Fuller if ((error = bhnd_nvram_plist_append(*props, prop)))
967a7c43ebdSLandon J. Fuller goto failed;
968a7c43ebdSLandon J. Fuller }
969a7c43ebdSLandon J. Fuller
970a7c43ebdSLandon J. Fuller /* Export complete */
971a7c43ebdSLandon J. Fuller finished:
972a7c43ebdSLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
973a7c43ebdSLandon J. Fuller
974a7c43ebdSLandon J. Fuller if (unordered != NULL)
975a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(unordered);
976a7c43ebdSLandon J. Fuller
977a7c43ebdSLandon J. Fuller return (0);
978a7c43ebdSLandon J. Fuller
979a7c43ebdSLandon J. Fuller failed:
980a7c43ebdSLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
981a7c43ebdSLandon J. Fuller
982a7c43ebdSLandon J. Fuller if (unordered != NULL)
983a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(unordered);
984a7c43ebdSLandon J. Fuller
985a7c43ebdSLandon J. Fuller if (options != NULL && *options != NULL)
986a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(*options);
987a7c43ebdSLandon J. Fuller
988a7c43ebdSLandon J. Fuller if (*props != NULL)
989a7c43ebdSLandon J. Fuller bhnd_nvram_plist_release(*props);
990a7c43ebdSLandon J. Fuller
991a7c43ebdSLandon J. Fuller return (error);
992a7c43ebdSLandon J. Fuller }
993a7c43ebdSLandon J. Fuller
99419be09f3SLandon J. Fuller /**
995c283839dSLandon J. Fuller * Encode all NVRAM properties at @p path, using the @p store's current NVRAM
996c283839dSLandon J. Fuller * data format.
997c283839dSLandon J. Fuller *
998c283839dSLandon J. Fuller * @param sc The NVRAM store instance.
999c283839dSLandon J. Fuller * @param path The NVRAM path to export, or NULL to select the root
1000c283839dSLandon J. Fuller * path.
1001c283839dSLandon J. Fuller * @param[out] data On success, will be set to the newly serialized value.
1002c283839dSLandon J. Fuller * The caller is responsible for freeing this value
1003c283839dSLandon J. Fuller * via bhnd_nvram_io_free().
1004c283839dSLandon J. Fuller * @param flags Export flags. See BHND_NVSTORE_EXPORT_*.
1005c283839dSLandon J. Fuller *
1006c283839dSLandon J. Fuller * @retval 0 success
1007c283839dSLandon J. Fuller * @retval EINVAL If @p flags is invalid.
1008c283839dSLandon J. Fuller * @retval ENOENT The requested path was not found.
1009c283839dSLandon J. Fuller * @retval ENOMEM If allocation fails.
1010c283839dSLandon J. Fuller * @retval non-zero If serialization of @p path otherwise fails, a regular
1011c283839dSLandon J. Fuller * unix error code will be returned.
1012c283839dSLandon J. Fuller */
1013c283839dSLandon J. Fuller int
bhnd_nvram_store_serialize(struct bhnd_nvram_store * sc,const char * path,struct bhnd_nvram_io ** data,uint32_t flags)1014c283839dSLandon J. Fuller bhnd_nvram_store_serialize(struct bhnd_nvram_store *sc, const char *path,
1015c283839dSLandon J. Fuller struct bhnd_nvram_io **data, uint32_t flags)
1016c283839dSLandon J. Fuller {
1017c283839dSLandon J. Fuller bhnd_nvram_plist *props;
1018c283839dSLandon J. Fuller bhnd_nvram_plist *options;
1019c283839dSLandon J. Fuller bhnd_nvram_data_class *cls;
1020c283839dSLandon J. Fuller struct bhnd_nvram_io *io;
1021c283839dSLandon J. Fuller void *outp;
1022c283839dSLandon J. Fuller size_t olen;
1023c283839dSLandon J. Fuller int error;
1024c283839dSLandon J. Fuller
1025c283839dSLandon J. Fuller props = NULL;
1026c283839dSLandon J. Fuller options = NULL;
1027c283839dSLandon J. Fuller io = NULL;
1028c283839dSLandon J. Fuller
1029c283839dSLandon J. Fuller /* Perform requested export */
1030c283839dSLandon J. Fuller error = bhnd_nvram_store_export(sc, path, &cls, &props, &options,
1031c283839dSLandon J. Fuller flags);
1032c283839dSLandon J. Fuller if (error)
1033c283839dSLandon J. Fuller return (error);
1034c283839dSLandon J. Fuller
1035c283839dSLandon J. Fuller /* Determine serialized size */
1036c283839dSLandon J. Fuller error = bhnd_nvram_data_serialize(cls, props, options, NULL, &olen);
1037c283839dSLandon J. Fuller if (error)
1038c283839dSLandon J. Fuller goto failed;
1039c283839dSLandon J. Fuller
1040c283839dSLandon J. Fuller /* Allocate output buffer */
1041c283839dSLandon J. Fuller if ((io = bhnd_nvram_iobuf_empty(olen, olen)) == NULL) {
1042c283839dSLandon J. Fuller error = ENOMEM;
1043c283839dSLandon J. Fuller goto failed;
1044c283839dSLandon J. Fuller }
1045c283839dSLandon J. Fuller
1046c283839dSLandon J. Fuller /* Fetch write pointer */
1047c283839dSLandon J. Fuller if ((error = bhnd_nvram_io_write_ptr(io, 0, &outp, olen, NULL)))
1048c283839dSLandon J. Fuller goto failed;
1049c283839dSLandon J. Fuller
1050c283839dSLandon J. Fuller /* Perform serialization */
1051c283839dSLandon J. Fuller error = bhnd_nvram_data_serialize(cls, props, options, outp, &olen);
1052c283839dSLandon J. Fuller if (error)
1053c283839dSLandon J. Fuller goto failed;
1054c283839dSLandon J. Fuller
1055c283839dSLandon J. Fuller if ((error = bhnd_nvram_io_setsize(io, olen)))
1056c283839dSLandon J. Fuller goto failed;
1057c283839dSLandon J. Fuller
1058c283839dSLandon J. Fuller /* Success */
1059c283839dSLandon J. Fuller bhnd_nvram_plist_release(props);
1060c283839dSLandon J. Fuller bhnd_nvram_plist_release(options);
1061c283839dSLandon J. Fuller
1062c283839dSLandon J. Fuller *data = io;
1063c283839dSLandon J. Fuller return (0);
1064c283839dSLandon J. Fuller
1065c283839dSLandon J. Fuller failed:
1066c283839dSLandon J. Fuller if (props != NULL)
1067c283839dSLandon J. Fuller bhnd_nvram_plist_release(props);
1068c283839dSLandon J. Fuller
1069c283839dSLandon J. Fuller if (options != NULL)
1070c283839dSLandon J. Fuller bhnd_nvram_plist_release(options);
1071c283839dSLandon J. Fuller
1072c283839dSLandon J. Fuller if (io != NULL)
1073c283839dSLandon J. Fuller bhnd_nvram_io_free(io);
1074c283839dSLandon J. Fuller
1075c283839dSLandon J. Fuller return (error);
1076c283839dSLandon J. Fuller }
1077c283839dSLandon J. Fuller
1078c283839dSLandon J. Fuller /**
107977cb4d3eSLandon J. Fuller * Read an NVRAM variable.
108077cb4d3eSLandon J. Fuller *
108177cb4d3eSLandon J. Fuller * @param sc The NVRAM parser state.
108277cb4d3eSLandon J. Fuller * @param name The NVRAM variable name.
108319be09f3SLandon J. Fuller * @param[out] outp On success, the requested value will be written
108477cb4d3eSLandon J. Fuller * to this buffer. This argment may be NULL if
108577cb4d3eSLandon J. Fuller * the value is not desired.
108619be09f3SLandon J. Fuller * @param[in,out] olen The capacity of @p outp. On success, will be set
108777cb4d3eSLandon J. Fuller * to the actual size of the requested value.
108819be09f3SLandon J. Fuller * @param otype The requested data type to be written to
108919be09f3SLandon J. Fuller * @p outp.
109077cb4d3eSLandon J. Fuller *
109177cb4d3eSLandon J. Fuller * @retval 0 success
109277cb4d3eSLandon J. Fuller * @retval ENOENT The requested variable was not found.
109319be09f3SLandon J. Fuller * @retval ENOMEM If @p outp is non-NULL and a buffer of @p olen is too
109477cb4d3eSLandon J. Fuller * small to hold the requested value.
109577cb4d3eSLandon J. Fuller * @retval non-zero If reading @p name otherwise fails, a regular unix
109677cb4d3eSLandon J. Fuller * error code will be returned.
109777cb4d3eSLandon J. Fuller */
109877cb4d3eSLandon J. Fuller int
bhnd_nvram_store_getvar(struct bhnd_nvram_store * sc,const char * name,void * outp,size_t * olen,bhnd_nvram_type otype)109977cb4d3eSLandon J. Fuller bhnd_nvram_store_getvar(struct bhnd_nvram_store *sc, const char *name,
110019be09f3SLandon J. Fuller void *outp, size_t *olen, bhnd_nvram_type otype)
110177cb4d3eSLandon J. Fuller {
110219be09f3SLandon J. Fuller bhnd_nvstore_name_info info;
110319be09f3SLandon J. Fuller bhnd_nvstore_path *path;
110419be09f3SLandon J. Fuller bhnd_nvram_prop *prop;
110577cb4d3eSLandon J. Fuller void *cookiep;
110677cb4d3eSLandon J. Fuller int error;
110777cb4d3eSLandon J. Fuller
110877cb4d3eSLandon J. Fuller BHND_NVSTORE_LOCK(sc);
110977cb4d3eSLandon J. Fuller
111019be09f3SLandon J. Fuller /* Parse the variable name */
111119be09f3SLandon J. Fuller error = bhnd_nvstore_parse_name_info(name, BHND_NVSTORE_NAME_EXTERNAL,
111219be09f3SLandon J. Fuller sc->data_caps, &info);
111319be09f3SLandon J. Fuller if (error)
111419be09f3SLandon J. Fuller goto finished;
111519be09f3SLandon J. Fuller
111619be09f3SLandon J. Fuller /* Fetch the variable's enclosing path entry */
111719be09f3SLandon J. Fuller if ((path = bhnd_nvstore_var_get_path(sc, &info)) == NULL) {
111819be09f3SLandon J. Fuller error = ENOENT;
111919be09f3SLandon J. Fuller goto finished;
112077cb4d3eSLandon J. Fuller }
112177cb4d3eSLandon J. Fuller
112219be09f3SLandon J. Fuller /* Search uncommitted updates first */
112319be09f3SLandon J. Fuller prop = bhnd_nvstore_path_get_update(sc, path, info.name);
112419be09f3SLandon J. Fuller if (prop != NULL) {
112519be09f3SLandon J. Fuller if (bhnd_nvram_prop_is_null(prop)) {
112619be09f3SLandon J. Fuller /* NULL denotes a pending deletion */
112719be09f3SLandon J. Fuller error = ENOENT;
112819be09f3SLandon J. Fuller } else {
112919be09f3SLandon J. Fuller error = bhnd_nvram_prop_encode(prop, outp, olen, otype);
113019be09f3SLandon J. Fuller }
113119be09f3SLandon J. Fuller goto finished;
113219be09f3SLandon J. Fuller }
113377cb4d3eSLandon J. Fuller
113419be09f3SLandon J. Fuller /* Search the backing NVRAM data */
113519be09f3SLandon J. Fuller cookiep = bhnd_nvstore_path_data_lookup(sc, path, info.name);
113619be09f3SLandon J. Fuller if (cookiep != NULL) {
113719be09f3SLandon J. Fuller /* Found in backing store */
113819be09f3SLandon J. Fuller error = bhnd_nvram_data_getvar(sc->data, cookiep, outp, olen,
113919be09f3SLandon J. Fuller otype);
114019be09f3SLandon J. Fuller goto finished;
114119be09f3SLandon J. Fuller }
114277cb4d3eSLandon J. Fuller
114319be09f3SLandon J. Fuller /* Not found */
114419be09f3SLandon J. Fuller error = ENOENT;
114519be09f3SLandon J. Fuller
114619be09f3SLandon J. Fuller finished:
114777cb4d3eSLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
114877cb4d3eSLandon J. Fuller return (error);
114977cb4d3eSLandon J. Fuller }
115077cb4d3eSLandon J. Fuller
115119be09f3SLandon J. Fuller /**
115219be09f3SLandon J. Fuller * Common bhnd_nvram_store_set*() and bhnd_nvram_store_unsetvar()
115319be09f3SLandon J. Fuller * implementation.
115419be09f3SLandon J. Fuller *
115519be09f3SLandon J. Fuller * If @p value is NULL, the variable will be marked for deletion.
115619be09f3SLandon J. Fuller */
115719be09f3SLandon J. Fuller static int
bhnd_nvram_store_setval_common(struct bhnd_nvram_store * sc,const char * name,bhnd_nvram_val * value)115819be09f3SLandon J. Fuller bhnd_nvram_store_setval_common(struct bhnd_nvram_store *sc, const char *name,
115919be09f3SLandon J. Fuller bhnd_nvram_val *value)
116019be09f3SLandon J. Fuller {
116119be09f3SLandon J. Fuller bhnd_nvstore_path *path;
116219be09f3SLandon J. Fuller bhnd_nvstore_name_info info;
116319be09f3SLandon J. Fuller int error;
116419be09f3SLandon J. Fuller
116519be09f3SLandon J. Fuller BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
116619be09f3SLandon J. Fuller
116719be09f3SLandon J. Fuller /* Parse the variable name */
116819be09f3SLandon J. Fuller error = bhnd_nvstore_parse_name_info(name, BHND_NVSTORE_NAME_EXTERNAL,
116919be09f3SLandon J. Fuller sc->data_caps, &info);
117019be09f3SLandon J. Fuller if (error)
117119be09f3SLandon J. Fuller return (error);
117219be09f3SLandon J. Fuller
117319be09f3SLandon J. Fuller /* Fetch the variable's enclosing path entry */
117419be09f3SLandon J. Fuller if ((path = bhnd_nvstore_var_get_path(sc, &info)) == NULL)
117519be09f3SLandon J. Fuller return (error);
117619be09f3SLandon J. Fuller
117719be09f3SLandon J. Fuller /* Register the update entry */
117819be09f3SLandon J. Fuller return (bhnd_nvstore_path_register_update(sc, path, info.name, value));
117977cb4d3eSLandon J. Fuller }
118077cb4d3eSLandon J. Fuller
118119be09f3SLandon J. Fuller /**
118219be09f3SLandon J. Fuller * Set an NVRAM variable.
118319be09f3SLandon J. Fuller *
118419be09f3SLandon J. Fuller * @param sc The NVRAM parser state.
118519be09f3SLandon J. Fuller * @param name The NVRAM variable name.
118619be09f3SLandon J. Fuller * @param value The new value.
118719be09f3SLandon J. Fuller *
118819be09f3SLandon J. Fuller * @retval 0 success
118919be09f3SLandon J. Fuller * @retval ENOENT The requested variable @p name was not found.
119019be09f3SLandon J. Fuller * @retval EINVAL If @p value is invalid.
119119be09f3SLandon J. Fuller */
119219be09f3SLandon J. Fuller int
bhnd_nvram_store_setval(struct bhnd_nvram_store * sc,const char * name,bhnd_nvram_val * value)119319be09f3SLandon J. Fuller bhnd_nvram_store_setval(struct bhnd_nvram_store *sc, const char *name,
119419be09f3SLandon J. Fuller bhnd_nvram_val *value)
119519be09f3SLandon J. Fuller {
119619be09f3SLandon J. Fuller int error;
119719be09f3SLandon J. Fuller
119819be09f3SLandon J. Fuller BHND_NVSTORE_LOCK(sc);
119919be09f3SLandon J. Fuller error = bhnd_nvram_store_setval_common(sc, name, value);
120077cb4d3eSLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
120177cb4d3eSLandon J. Fuller
120277cb4d3eSLandon J. Fuller return (error);
120377cb4d3eSLandon J. Fuller }
120477cb4d3eSLandon J. Fuller
120577cb4d3eSLandon J. Fuller /**
120677cb4d3eSLandon J. Fuller * Set an NVRAM variable.
120777cb4d3eSLandon J. Fuller *
120877cb4d3eSLandon J. Fuller * @param sc The NVRAM parser state.
120977cb4d3eSLandon J. Fuller * @param name The NVRAM variable name.
121019be09f3SLandon J. Fuller * @param[out] inp The new value.
121119be09f3SLandon J. Fuller * @param[in,out] ilen The size of @p inp.
121219be09f3SLandon J. Fuller * @param itype The data type of @p inp.
121377cb4d3eSLandon J. Fuller *
121477cb4d3eSLandon J. Fuller * @retval 0 success
121519be09f3SLandon J. Fuller * @retval ENOENT The requested variable @p name was not found.
121619be09f3SLandon J. Fuller * @retval EINVAL If the new value is invalid.
121719be09f3SLandon J. Fuller * @retval EINVAL If @p name is read-only.
121877cb4d3eSLandon J. Fuller */
121977cb4d3eSLandon J. Fuller int
bhnd_nvram_store_setvar(struct bhnd_nvram_store * sc,const char * name,const void * inp,size_t ilen,bhnd_nvram_type itype)122077cb4d3eSLandon J. Fuller bhnd_nvram_store_setvar(struct bhnd_nvram_store *sc, const char *name,
122119be09f3SLandon J. Fuller const void *inp, size_t ilen, bhnd_nvram_type itype)
122277cb4d3eSLandon J. Fuller {
122319be09f3SLandon J. Fuller bhnd_nvram_val val;
122477cb4d3eSLandon J. Fuller int error;
122577cb4d3eSLandon J. Fuller
122619be09f3SLandon J. Fuller error = bhnd_nvram_val_init(&val, NULL, inp, ilen, itype,
122719be09f3SLandon J. Fuller BHND_NVRAM_VAL_FIXED|BHND_NVRAM_VAL_BORROW_DATA);
122877cb4d3eSLandon J. Fuller if (error) {
122919be09f3SLandon J. Fuller BHND_NV_LOG("error initializing value: %d\n", error);
123019be09f3SLandon J. Fuller return (EINVAL);
123119be09f3SLandon J. Fuller }
123219be09f3SLandon J. Fuller
123319be09f3SLandon J. Fuller BHND_NVSTORE_LOCK(sc);
123419be09f3SLandon J. Fuller error = bhnd_nvram_store_setval_common(sc, name, &val);
123519be09f3SLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
123619be09f3SLandon J. Fuller
123719be09f3SLandon J. Fuller bhnd_nvram_val_release(&val);
123819be09f3SLandon J. Fuller
123977cb4d3eSLandon J. Fuller return (error);
124077cb4d3eSLandon J. Fuller }
124177cb4d3eSLandon J. Fuller
124277cb4d3eSLandon J. Fuller /**
124319be09f3SLandon J. Fuller * Unset an NVRAM variable.
124477cb4d3eSLandon J. Fuller *
124577cb4d3eSLandon J. Fuller * @param sc The NVRAM parser state.
124619be09f3SLandon J. Fuller * @param name The NVRAM variable name.
124777cb4d3eSLandon J. Fuller *
124877cb4d3eSLandon J. Fuller * @retval 0 success
124919be09f3SLandon J. Fuller * @retval ENOENT The requested variable @p name was not found.
125019be09f3SLandon J. Fuller * @retval EINVAL If @p name is read-only.
125177cb4d3eSLandon J. Fuller */
125219be09f3SLandon J. Fuller int
bhnd_nvram_store_unsetvar(struct bhnd_nvram_store * sc,const char * name)125319be09f3SLandon J. Fuller bhnd_nvram_store_unsetvar(struct bhnd_nvram_store *sc, const char *name)
125477cb4d3eSLandon J. Fuller {
125577cb4d3eSLandon J. Fuller int error;
125677cb4d3eSLandon J. Fuller
125719be09f3SLandon J. Fuller BHND_NVSTORE_LOCK(sc);
125819be09f3SLandon J. Fuller error = bhnd_nvram_store_setval_common(sc, name, BHND_NVRAM_VAL_NULL);
125919be09f3SLandon J. Fuller BHND_NVSTORE_UNLOCK(sc);
126019be09f3SLandon J. Fuller
126177cb4d3eSLandon J. Fuller return (error);
126277cb4d3eSLandon J. Fuller }
1263