xref: /freebsd/sys/dev/bhnd/nvram/bhnd_nvram_store_subr.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
119be09f3SLandon J. Fuller /*-
219be09f3SLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
319be09f3SLandon J. Fuller  * All rights reserved.
419be09f3SLandon J. Fuller  *
519be09f3SLandon J. Fuller  * Redistribution and use in source and binary forms, with or without
619be09f3SLandon J. Fuller  * modification, are permitted provided that the following conditions
719be09f3SLandon J. Fuller  * are met:
819be09f3SLandon J. Fuller  * 1. Redistributions of source code must retain the above copyright
919be09f3SLandon J. Fuller  *    notice, this list of conditions and the following disclaimer,
1019be09f3SLandon J. Fuller  *    without modification.
1119be09f3SLandon J. Fuller  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1219be09f3SLandon J. Fuller  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1319be09f3SLandon J. Fuller  *    redistribution must be conditioned upon including a substantially
1419be09f3SLandon J. Fuller  *    similar Disclaimer requirement for further binary redistribution.
1519be09f3SLandon J. Fuller  *
1619be09f3SLandon J. Fuller  * NO WARRANTY
1719be09f3SLandon J. Fuller  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1819be09f3SLandon J. Fuller  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1919be09f3SLandon J. Fuller  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2019be09f3SLandon J. Fuller  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2119be09f3SLandon J. Fuller  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2219be09f3SLandon J. Fuller  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2319be09f3SLandon J. Fuller  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2419be09f3SLandon J. Fuller  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2519be09f3SLandon J. Fuller  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2619be09f3SLandon J. Fuller  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2719be09f3SLandon J. Fuller  * THE POSSIBILITY OF SUCH DAMAGES.
2819be09f3SLandon J. Fuller  */
2919be09f3SLandon J. Fuller 
3019be09f3SLandon J. Fuller #include <sys/param.h>
3119be09f3SLandon J. Fuller #include <sys/hash.h>
3219be09f3SLandon J. Fuller #include <sys/queue.h>
3319be09f3SLandon J. Fuller 
3419be09f3SLandon J. Fuller #ifdef _KERNEL
3519be09f3SLandon J. Fuller 
3619be09f3SLandon J. Fuller #include <sys/ctype.h>
3719be09f3SLandon J. Fuller #include <sys/systm.h>
3819be09f3SLandon J. Fuller 
3919be09f3SLandon J. Fuller #include <machine/_inttypes.h>
4019be09f3SLandon J. Fuller 
4119be09f3SLandon J. Fuller #else /* !_KERNEL */
4219be09f3SLandon J. Fuller 
4319be09f3SLandon J. Fuller #include <ctype.h>
4419be09f3SLandon J. Fuller #include <errno.h>
4519be09f3SLandon J. Fuller #include <inttypes.h>
4619be09f3SLandon J. Fuller #include <stdbool.h>
4719be09f3SLandon J. Fuller #include <stdio.h>
4819be09f3SLandon J. Fuller #include <stdint.h>
4919be09f3SLandon J. Fuller #include <stdlib.h>
5019be09f3SLandon J. Fuller #include <string.h>
5119be09f3SLandon J. Fuller 
5219be09f3SLandon J. Fuller #endif /* _KERNEL */
5319be09f3SLandon J. Fuller 
5419be09f3SLandon J. Fuller #include "bhnd_nvram_private.h"
5519be09f3SLandon J. Fuller #include "bhnd_nvram_datavar.h"
5619be09f3SLandon J. Fuller 
5719be09f3SLandon J. Fuller #include "bhnd_nvram_storevar.h"
5819be09f3SLandon J. Fuller 
59*af3c7888SEd Schouten static int bhnd_nvstore_idx_cmp(const void *lhs, const void *rhs, void *ctx);
6019be09f3SLandon J. Fuller 
6119be09f3SLandon J. Fuller /**
6219be09f3SLandon J. Fuller  * Allocate and initialize a new path instance.
6319be09f3SLandon J. Fuller  *
6419be09f3SLandon J. Fuller  * The caller is responsible for deallocating the instance via
6519be09f3SLandon J. Fuller  * bhnd_nvstore_path_free().
6619be09f3SLandon J. Fuller  *
6719be09f3SLandon J. Fuller  * @param	path_str	The path's canonical string representation.
6819be09f3SLandon J. Fuller  * @param	path_len	The length of @p path_str.
6919be09f3SLandon J. Fuller  *
7019be09f3SLandon J. Fuller  * @retval non-NULL	success
7119be09f3SLandon J. Fuller  * @retval NULL		if allocation fails.
7219be09f3SLandon J. Fuller  */
7319be09f3SLandon J. Fuller bhnd_nvstore_path *
bhnd_nvstore_path_new(const char * path_str,size_t path_len)7419be09f3SLandon J. Fuller bhnd_nvstore_path_new(const char *path_str, size_t path_len)
7519be09f3SLandon J. Fuller {
7619be09f3SLandon J. Fuller 	bhnd_nvstore_path *path;
7719be09f3SLandon J. Fuller 
7819be09f3SLandon J. Fuller 	/* Allocate new entry */
7919be09f3SLandon J. Fuller 	path = bhnd_nv_malloc(sizeof(*path));
8019be09f3SLandon J. Fuller 	if (path == NULL)
8119be09f3SLandon J. Fuller 		return (NULL);
8219be09f3SLandon J. Fuller 
8319be09f3SLandon J. Fuller 	path->index = NULL;
8419be09f3SLandon J. Fuller 	path->num_vars = 0;
8519be09f3SLandon J. Fuller 
8619be09f3SLandon J. Fuller 	path->pending = bhnd_nvram_plist_new();
8719be09f3SLandon J. Fuller 	if (path->pending == NULL)
8819be09f3SLandon J. Fuller 		goto failed;
8919be09f3SLandon J. Fuller 
9019be09f3SLandon J. Fuller 	path->path_str = bhnd_nv_strndup(path_str, path_len);
9119be09f3SLandon J. Fuller 	if (path->path_str == NULL)
9219be09f3SLandon J. Fuller 		goto failed;
9319be09f3SLandon J. Fuller 
9419be09f3SLandon J. Fuller 	return (path);
9519be09f3SLandon J. Fuller 
9619be09f3SLandon J. Fuller failed:
9719be09f3SLandon J. Fuller 	if (path->pending != NULL)
9819be09f3SLandon J. Fuller 		bhnd_nvram_plist_release(path->pending);
9919be09f3SLandon J. Fuller 
10019be09f3SLandon J. Fuller 	if (path->path_str != NULL)
10119be09f3SLandon J. Fuller 		bhnd_nv_free(path->path_str);
10219be09f3SLandon J. Fuller 
10319be09f3SLandon J. Fuller 	bhnd_nv_free(path);
10419be09f3SLandon J. Fuller 
10519be09f3SLandon J. Fuller 	return (NULL);
10619be09f3SLandon J. Fuller }
10719be09f3SLandon J. Fuller 
10819be09f3SLandon J. Fuller /**
10919be09f3SLandon J. Fuller  * Free an NVRAM path instance, releasing all associated resources.
11019be09f3SLandon J. Fuller  */
11119be09f3SLandon J. Fuller void
bhnd_nvstore_path_free(struct bhnd_nvstore_path * path)11219be09f3SLandon J. Fuller bhnd_nvstore_path_free(struct bhnd_nvstore_path *path)
11319be09f3SLandon J. Fuller {
11419be09f3SLandon J. Fuller 	/* Free the per-path index */
11519be09f3SLandon J. Fuller 	if (path->index != NULL)
11619be09f3SLandon J. Fuller 		bhnd_nvstore_index_free(path->index);
11719be09f3SLandon J. Fuller 
11819be09f3SLandon J. Fuller 	bhnd_nvram_plist_release(path->pending);
11919be09f3SLandon J. Fuller 	bhnd_nv_free(path->path_str);
12019be09f3SLandon J. Fuller 	bhnd_nv_free(path);
12119be09f3SLandon J. Fuller }
12219be09f3SLandon J. Fuller 
12319be09f3SLandon J. Fuller /**
12419be09f3SLandon J. Fuller  * Allocate and initialize a new index instance with @p capacity.
12519be09f3SLandon J. Fuller  *
12619be09f3SLandon J. Fuller  * The caller is responsible for deallocating the instance via
12719be09f3SLandon J. Fuller  * bhnd_nvstore_index_free().
12819be09f3SLandon J. Fuller  *
12919be09f3SLandon J. Fuller  * @param	capacity	The maximum number of variables to be indexed.
13019be09f3SLandon J. Fuller  *
13119be09f3SLandon J. Fuller  * @retval non-NULL	success
13219be09f3SLandon J. Fuller  * @retval NULL		if allocation fails.
13319be09f3SLandon J. Fuller  */
13419be09f3SLandon J. Fuller bhnd_nvstore_index *
bhnd_nvstore_index_new(size_t capacity)13519be09f3SLandon J. Fuller bhnd_nvstore_index_new(size_t capacity)
13619be09f3SLandon J. Fuller {
13719be09f3SLandon J. Fuller 	bhnd_nvstore_index	*index;
13819be09f3SLandon J. Fuller 	size_t			 bytes;
13919be09f3SLandon J. Fuller 
14019be09f3SLandon J. Fuller 	/* Allocate and populate variable index */
14119be09f3SLandon J. Fuller 	bytes = sizeof(struct bhnd_nvstore_index) + (sizeof(void *) * capacity);
14219be09f3SLandon J. Fuller 	index = bhnd_nv_malloc(bytes);
14319be09f3SLandon J. Fuller 	if (index == NULL) {
14419be09f3SLandon J. Fuller 		BHND_NV_LOG("error allocating %zu byte index\n", bytes);
14519be09f3SLandon J. Fuller 		return (NULL);
14619be09f3SLandon J. Fuller 	}
14719be09f3SLandon J. Fuller 
14819be09f3SLandon J. Fuller 	index->count = 0;
14919be09f3SLandon J. Fuller 	index->capacity = capacity;
15019be09f3SLandon J. Fuller 
15119be09f3SLandon J. Fuller 	return (index);
15219be09f3SLandon J. Fuller }
15319be09f3SLandon J. Fuller 
15419be09f3SLandon J. Fuller /**
15519be09f3SLandon J. Fuller  * Free an index instance, releasing all associated resources.
15619be09f3SLandon J. Fuller  *
15719be09f3SLandon J. Fuller  * @param	index	An index instance previously allocated via
15819be09f3SLandon J. Fuller  *			bhnd_nvstore_index_new().
15919be09f3SLandon J. Fuller  */
16019be09f3SLandon J. Fuller void
bhnd_nvstore_index_free(bhnd_nvstore_index * index)16119be09f3SLandon J. Fuller bhnd_nvstore_index_free(bhnd_nvstore_index *index)
16219be09f3SLandon J. Fuller {
16319be09f3SLandon J. Fuller 	bhnd_nv_free(index);
16419be09f3SLandon J. Fuller }
16519be09f3SLandon J. Fuller 
16619be09f3SLandon J. Fuller /**
16719be09f3SLandon J. Fuller  * Append a new NVRAM variable's @p cookiep value to @p index.
16819be09f3SLandon J. Fuller  *
16919be09f3SLandon J. Fuller  * After one or more append requests, the index must be prepared via
17019be09f3SLandon J. Fuller  * bhnd_nvstore_index_prepare() before any indexed lookups are performed.
17119be09f3SLandon J. Fuller  *
17219be09f3SLandon J. Fuller  * @param	sc	The NVRAM store from which NVRAM values will be queried.
17319be09f3SLandon J. Fuller  * @param	index	The index to be modified.
17419be09f3SLandon J. Fuller  * @param	cookiep	The cookiep value (as provided by the backing NVRAM
17519be09f3SLandon J. Fuller  *			data instance of @p sc) to be included in @p index.
17619be09f3SLandon J. Fuller  *
17719be09f3SLandon J. Fuller  * @retval 0		success
17819be09f3SLandon J. Fuller  * @retval ENOMEM	if appending an additional entry would exceed the
17919be09f3SLandon J. Fuller  *			capacity of @p index.
18019be09f3SLandon J. Fuller  */
18119be09f3SLandon J. Fuller int
bhnd_nvstore_index_append(struct bhnd_nvram_store * sc,bhnd_nvstore_index * index,void * cookiep)18219be09f3SLandon J. Fuller bhnd_nvstore_index_append(struct bhnd_nvram_store *sc,
18319be09f3SLandon J. Fuller     bhnd_nvstore_index *index, void *cookiep)
18419be09f3SLandon J. Fuller {
18519be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
18619be09f3SLandon J. Fuller 
18719be09f3SLandon J. Fuller 	if (index->count >= index->capacity)
18819be09f3SLandon J. Fuller 		return (ENOMEM);
18919be09f3SLandon J. Fuller 
19019be09f3SLandon J. Fuller 	index->cookiep[index->count] = cookiep;
19119be09f3SLandon J. Fuller 	index->count++;
19219be09f3SLandon J. Fuller 	return (0);
19319be09f3SLandon J. Fuller }
19419be09f3SLandon J. Fuller 
19519be09f3SLandon J. Fuller /* sort function for bhnd_nvstore_index_prepare() */
19619be09f3SLandon J. Fuller static int
bhnd_nvstore_idx_cmp(const void * lhs,const void * rhs,void * ctx)197*af3c7888SEd Schouten bhnd_nvstore_idx_cmp(const void *lhs, const void *rhs, void *ctx)
19819be09f3SLandon J. Fuller {
19919be09f3SLandon J. Fuller 	struct bhnd_nvram_store	*sc;
20019be09f3SLandon J. Fuller 	void			*l_cookiep, *r_cookiep;
20119be09f3SLandon J. Fuller 	const char		*l_str, *r_str;
20219be09f3SLandon J. Fuller 	const char		*l_name, *r_name;
20319be09f3SLandon J. Fuller 	int			 order;
20419be09f3SLandon J. Fuller 
20519be09f3SLandon J. Fuller 	sc = ctx;
20619be09f3SLandon J. Fuller 	l_cookiep = *(void * const *)lhs;
20719be09f3SLandon J. Fuller 	r_cookiep = *(void * const *)rhs;
20819be09f3SLandon J. Fuller 
20919be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
21019be09f3SLandon J. Fuller 
21119be09f3SLandon J. Fuller 	/* Fetch string pointers from the cookiep values */
21219be09f3SLandon J. Fuller 	l_str = bhnd_nvram_data_getvar_name(sc->data, l_cookiep);
21319be09f3SLandon J. Fuller 	r_str = bhnd_nvram_data_getvar_name(sc->data, r_cookiep);
21419be09f3SLandon J. Fuller 
21519be09f3SLandon J. Fuller 	/* Trim device path prefixes */
21619be09f3SLandon J. Fuller 	if (sc->data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS) {
21719be09f3SLandon J. Fuller 		l_name = bhnd_nvram_trim_path_name(l_str);
21819be09f3SLandon J. Fuller 		r_name = bhnd_nvram_trim_path_name(r_str);
21919be09f3SLandon J. Fuller 	} else {
22019be09f3SLandon J. Fuller 		l_name = l_str;
22119be09f3SLandon J. Fuller 		r_name = r_str;
22219be09f3SLandon J. Fuller 	}
22319be09f3SLandon J. Fuller 
22419be09f3SLandon J. Fuller 	/* Perform comparison */
22519be09f3SLandon J. Fuller 	order = strcmp(l_name, r_name);
22619be09f3SLandon J. Fuller 	if (order != 0 || lhs == rhs)
22719be09f3SLandon J. Fuller 		return (order);
22819be09f3SLandon J. Fuller 
22919be09f3SLandon J. Fuller 	/* If the backing data incorrectly contains variables with duplicate
23019be09f3SLandon J. Fuller 	 * names, we need a sort order that provides stable behavior.
23119be09f3SLandon J. Fuller 	 *
23219be09f3SLandon J. Fuller 	 * Since Broadcom's own code varies wildly on this question, we just
23319be09f3SLandon J. Fuller 	 * use a simple precedence rule: The first declaration of a variable
23419be09f3SLandon J. Fuller 	 * takes precedence. */
23519be09f3SLandon J. Fuller 	return (bhnd_nvram_data_getvar_order(sc->data, l_cookiep, r_cookiep));
23619be09f3SLandon J. Fuller }
23719be09f3SLandon J. Fuller 
23819be09f3SLandon J. Fuller /**
23919be09f3SLandon J. Fuller  * Prepare @p index for querying via bhnd_nvstore_index_lookup().
24019be09f3SLandon J. Fuller  *
24119be09f3SLandon J. Fuller  * After one or more append requests, the index must be prepared via
24219be09f3SLandon J. Fuller  * bhnd_nvstore_index_prepare() before any indexed lookups are performed.
24319be09f3SLandon J. Fuller  *
24419be09f3SLandon J. Fuller  * @param	sc	The NVRAM store from which NVRAM values will be queried.
24519be09f3SLandon J. Fuller  * @param	index	The index to be prepared.
24619be09f3SLandon J. Fuller  *
24719be09f3SLandon J. Fuller  * @retval 0		success
24819be09f3SLandon J. Fuller  * @retval non-zero	if preparing @p index otherwise fails, a regular unix
24919be09f3SLandon J. Fuller  *			error code will be returned.
25019be09f3SLandon J. Fuller  */
25119be09f3SLandon J. Fuller int
bhnd_nvstore_index_prepare(struct bhnd_nvram_store * sc,bhnd_nvstore_index * index)25219be09f3SLandon J. Fuller bhnd_nvstore_index_prepare(struct bhnd_nvram_store *sc,
25319be09f3SLandon J. Fuller     bhnd_nvstore_index *index)
25419be09f3SLandon J. Fuller {
25519be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
25619be09f3SLandon J. Fuller 
25719be09f3SLandon J. Fuller 	/* Sort the index table */
258*af3c7888SEd Schouten 	qsort_r(index->cookiep, index->count, sizeof(index->cookiep[0]),
259*af3c7888SEd Schouten 	    bhnd_nvstore_idx_cmp, sc);
26019be09f3SLandon J. Fuller 
26119be09f3SLandon J. Fuller 	return (0);
26219be09f3SLandon J. Fuller }
26319be09f3SLandon J. Fuller 
26419be09f3SLandon J. Fuller /**
26519be09f3SLandon J. Fuller  * Return a borrowed reference to the root path node.
26619be09f3SLandon J. Fuller  *
26719be09f3SLandon J. Fuller  * @param	sc	The NVRAM store.
26819be09f3SLandon J. Fuller  */
26919be09f3SLandon J. Fuller bhnd_nvstore_path *
bhnd_nvstore_get_root_path(struct bhnd_nvram_store * sc)27019be09f3SLandon J. Fuller bhnd_nvstore_get_root_path(struct bhnd_nvram_store *sc)
27119be09f3SLandon J. Fuller {
27219be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
27319be09f3SLandon J. Fuller 	return (sc->root_path);
27419be09f3SLandon J. Fuller }
27519be09f3SLandon J. Fuller 
27619be09f3SLandon J. Fuller /**
27719be09f3SLandon J. Fuller  * Return true if @p path is the root path node.
27819be09f3SLandon J. Fuller  *
27919be09f3SLandon J. Fuller  * @param	sc	The NVRAM store.
28019be09f3SLandon J. Fuller  * @param	path	The path to query.
28119be09f3SLandon J. Fuller  */
28219be09f3SLandon J. Fuller bool
bhnd_nvstore_is_root_path(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path)28319be09f3SLandon J. Fuller bhnd_nvstore_is_root_path(struct bhnd_nvram_store *sc, bhnd_nvstore_path *path)
28419be09f3SLandon J. Fuller {
28519be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
28619be09f3SLandon J. Fuller 	return (sc->root_path == path);
28719be09f3SLandon J. Fuller }
28819be09f3SLandon J. Fuller 
28919be09f3SLandon J. Fuller /**
29019be09f3SLandon J. Fuller  * Return the update entry matching @p name in @p path, or NULL if no entry
29119be09f3SLandon J. Fuller  * found.
29219be09f3SLandon J. Fuller  *
29319be09f3SLandon J. Fuller  * @param sc	The NVRAM store.
29419be09f3SLandon J. Fuller  * @param path	The path to query.
29519be09f3SLandon J. Fuller  * @param name	The NVRAM variable name to search for in @p path's update list.
29619be09f3SLandon J. Fuller  *
29719be09f3SLandon J. Fuller  * @retval non-NULL	success
29819be09f3SLandon J. Fuller  * @retval NULL		if @p name is not found in @p path.
29919be09f3SLandon J. Fuller  */
30019be09f3SLandon J. Fuller bhnd_nvram_prop *
bhnd_nvstore_path_get_update(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,const char * name)30119be09f3SLandon J. Fuller bhnd_nvstore_path_get_update(struct bhnd_nvram_store *sc,
30219be09f3SLandon J. Fuller     bhnd_nvstore_path *path, const char *name)
30319be09f3SLandon J. Fuller {
30419be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
30519be09f3SLandon J. Fuller 	return (bhnd_nvram_plist_get_prop(path->pending, name));
30619be09f3SLandon J. Fuller }
30719be09f3SLandon J. Fuller 
30819be09f3SLandon J. Fuller /**
30919be09f3SLandon J. Fuller  * Register or remove an update record for @p name in @p path.
31019be09f3SLandon J. Fuller  *
31119be09f3SLandon J. Fuller  * @param sc	The NVRAM store.
31219be09f3SLandon J. Fuller  * @param path	The path to be modified.
31319be09f3SLandon J. Fuller  * @param name	The path-relative variable name to be modified.
31419be09f3SLandon J. Fuller  * @param value	The new value. A value of BHND_NVRAM_TYPE_NULL denotes deletion.
31519be09f3SLandon J. Fuller  *
31619be09f3SLandon J. Fuller  * @retval 0		success
31719be09f3SLandon J. Fuller  * @retval ENOMEM	if allocation fails.
31819be09f3SLandon J. Fuller  * @retval ENOENT	if @p name is unknown.
31919be09f3SLandon J. Fuller  * @retval EINVAL	if @p value is NULL, and deletion of @p is not
32019be09f3SLandon J. Fuller  *			supported.
32119be09f3SLandon J. Fuller  * @retval EINVAL	if @p value cannot be converted to a supported value
32219be09f3SLandon J. Fuller  *			type.
32319be09f3SLandon J. Fuller  */
32419be09f3SLandon J. Fuller int
bhnd_nvstore_path_register_update(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,const char * name,bhnd_nvram_val * value)32519be09f3SLandon J. Fuller bhnd_nvstore_path_register_update(struct bhnd_nvram_store *sc,
32619be09f3SLandon J. Fuller     bhnd_nvstore_path *path, const char *name, bhnd_nvram_val *value)
32719be09f3SLandon J. Fuller {
32819be09f3SLandon J. Fuller 	bhnd_nvram_val		*prop_val;
32919be09f3SLandon J. Fuller 	const char		*full_name;
33019be09f3SLandon J. Fuller 	void			*cookiep;
33119be09f3SLandon J. Fuller 	char			*namebuf;
33219be09f3SLandon J. Fuller 	int			 error;
33319be09f3SLandon J. Fuller 	bool			 nvram_committed;
33419be09f3SLandon J. Fuller 
33519be09f3SLandon J. Fuller 	namebuf = NULL;
33619be09f3SLandon J. Fuller 	prop_val = NULL;
33719be09f3SLandon J. Fuller 
33819be09f3SLandon J. Fuller 	/* Determine whether the variable is currently defined in the
33919be09f3SLandon J. Fuller 	 * backing NVRAM data, and derive its full path-prefixed name */
34019be09f3SLandon J. Fuller 	nvram_committed = false;
341a7c43ebdSLandon J. Fuller 	cookiep = bhnd_nvstore_path_data_lookup(sc, path, name);
34219be09f3SLandon J. Fuller 	if (cookiep != NULL) {
34319be09f3SLandon J. Fuller 		/* Variable is defined in the backing data */
34419be09f3SLandon J. Fuller 		nvram_committed = true;
34519be09f3SLandon J. Fuller 
34619be09f3SLandon J. Fuller 		/* Use the existing variable name */
34719be09f3SLandon J. Fuller 		full_name = bhnd_nvram_data_getvar_name(sc->data, cookiep);
34819be09f3SLandon J. Fuller 	} else if (path == sc->root_path) {
34919be09f3SLandon J. Fuller 		/* No prefix required for root path */
35019be09f3SLandon J. Fuller 		full_name = name;
35119be09f3SLandon J. Fuller 	} else {
35219be09f3SLandon J. Fuller 		bhnd_nvstore_alias	*alias;
35319be09f3SLandon J. Fuller 		int			 len;
35419be09f3SLandon J. Fuller 
35519be09f3SLandon J. Fuller 		/* New variable is being set; we need to determine the
35619be09f3SLandon J. Fuller 		 * appropriate path prefix */
35719be09f3SLandon J. Fuller 		alias = bhnd_nvstore_find_alias(sc, path->path_str);
35819be09f3SLandon J. Fuller 		if (alias != NULL) {
35919be09f3SLandon J. Fuller 			/* Use <alias>:name */
36019be09f3SLandon J. Fuller 			len = bhnd_nv_asprintf(&namebuf, "%lu:%s", alias->alias,
36119be09f3SLandon J. Fuller 			    name);
36219be09f3SLandon J. Fuller 		} else {
36319be09f3SLandon J. Fuller 			/* Use path/name */
36419be09f3SLandon J. Fuller 			len = bhnd_nv_asprintf(&namebuf, "%s/%s",
36519be09f3SLandon J. Fuller 			    path->path_str, name);
36619be09f3SLandon J. Fuller 		}
36719be09f3SLandon J. Fuller 
36819be09f3SLandon J. Fuller 		if (len < 0)
36919be09f3SLandon J. Fuller 			return (ENOMEM);
37019be09f3SLandon J. Fuller 
37119be09f3SLandon J. Fuller 		full_name = namebuf;
37219be09f3SLandon J. Fuller 	}
37319be09f3SLandon J. Fuller 
37419be09f3SLandon J. Fuller 	/* Allow the data store to filter the NVRAM operation */
37519be09f3SLandon J. Fuller 	if (bhnd_nvram_val_type(value) == BHND_NVRAM_TYPE_NULL) {
37619be09f3SLandon J. Fuller 		error = bhnd_nvram_data_filter_unsetvar(sc->data, full_name);
37719be09f3SLandon J. Fuller 		if (error) {
37819be09f3SLandon J. Fuller 			BHND_NV_LOG("cannot unset property %s: %d\n", full_name,
37919be09f3SLandon J. Fuller 			    error);
38019be09f3SLandon J. Fuller 			goto cleanup;
38119be09f3SLandon J. Fuller 		}
38219be09f3SLandon J. Fuller 
38319be09f3SLandon J. Fuller 		if ((prop_val = bhnd_nvram_val_copy(value)) == NULL) {
38419be09f3SLandon J. Fuller 			error = ENOMEM;
38519be09f3SLandon J. Fuller 			goto cleanup;
38619be09f3SLandon J. Fuller 		}
38719be09f3SLandon J. Fuller 	} else {
38819be09f3SLandon J. Fuller 		error = bhnd_nvram_data_filter_setvar(sc->data, full_name,
38919be09f3SLandon J. Fuller 		    value,  &prop_val);
39019be09f3SLandon J. Fuller 		if (error) {
39119be09f3SLandon J. Fuller 			BHND_NV_LOG("cannot set property %s: %d\n", full_name,
39219be09f3SLandon J. Fuller 			    error);
39319be09f3SLandon J. Fuller 			goto cleanup;
39419be09f3SLandon J. Fuller 		}
39519be09f3SLandon J. Fuller 	}
39619be09f3SLandon J. Fuller 
39719be09f3SLandon J. Fuller 	/* Add relative variable name to the per-path update list */
39819be09f3SLandon J. Fuller 	if (bhnd_nvram_val_type(value) == BHND_NVRAM_TYPE_NULL &&
39919be09f3SLandon J. Fuller 	    !nvram_committed)
40019be09f3SLandon J. Fuller 	{
40119be09f3SLandon J. Fuller 		/* This is a deletion request for a variable not defined in
40219be09f3SLandon J. Fuller 		 * out backing store; we can simply remove the corresponding
40319be09f3SLandon J. Fuller 		 * update entry. */
40419be09f3SLandon J. Fuller 		bhnd_nvram_plist_remove(path->pending, name);
40519be09f3SLandon J. Fuller 	} else {
40619be09f3SLandon J. Fuller 		/* Update or append a pending update entry */
40719be09f3SLandon J. Fuller 		error = bhnd_nvram_plist_replace_val(path->pending, name,
40819be09f3SLandon J. Fuller 		    prop_val);
40919be09f3SLandon J. Fuller 		if (error)
41019be09f3SLandon J. Fuller 			goto cleanup;
41119be09f3SLandon J. Fuller 	}
41219be09f3SLandon J. Fuller 
41319be09f3SLandon J. Fuller 	/* Success */
41419be09f3SLandon J. Fuller 	error = 0;
41519be09f3SLandon J. Fuller 
41619be09f3SLandon J. Fuller cleanup:
41719be09f3SLandon J. Fuller 	if (namebuf != NULL)
41819be09f3SLandon J. Fuller 		bhnd_nv_free(namebuf);
41919be09f3SLandon J. Fuller 
42019be09f3SLandon J. Fuller 	if (prop_val != NULL)
42119be09f3SLandon J. Fuller 		bhnd_nvram_val_release(prop_val);
42219be09f3SLandon J. Fuller 
42319be09f3SLandon J. Fuller 	return (error);
42419be09f3SLandon J. Fuller }
42519be09f3SLandon J. Fuller 
42619be09f3SLandon J. Fuller /**
42719be09f3SLandon J. Fuller  * Iterate over all variable cookiep values retrievable from the backing
42819be09f3SLandon J. Fuller  * data store in @p path.
42919be09f3SLandon J. Fuller  *
43019be09f3SLandon J. Fuller  * @warning Pending updates in @p path are ignored by this function.
43119be09f3SLandon J. Fuller  *
43219be09f3SLandon J. Fuller  * @param		sc	The NVRAM store.
43319be09f3SLandon J. Fuller  * @param		path	The NVRAM path to be iterated.
43419be09f3SLandon J. Fuller  * @param[in,out]	indexp	A pointer to an opaque indexp value previously
43519be09f3SLandon J. Fuller  *				returned by bhnd_nvstore_path_data_next(), or a
43619be09f3SLandon J. Fuller  *				NULL value to begin iteration.
43719be09f3SLandon J. Fuller  *
43819be09f3SLandon J. Fuller  * @return Returns the next variable name, or NULL if there are no more
43919be09f3SLandon J. Fuller  * variables defined in @p path.
44019be09f3SLandon J. Fuller  */
44119be09f3SLandon J. Fuller void *
bhnd_nvstore_path_data_next(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,void ** indexp)44219be09f3SLandon J. Fuller bhnd_nvstore_path_data_next(struct bhnd_nvram_store *sc,
44319be09f3SLandon J. Fuller      bhnd_nvstore_path *path, void **indexp)
44419be09f3SLandon J. Fuller {
44519be09f3SLandon J. Fuller 	void **index_ref;
44619be09f3SLandon J. Fuller 
44719be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
44819be09f3SLandon J. Fuller 
44919be09f3SLandon J. Fuller 	/* No index */
45019be09f3SLandon J. Fuller 	if (path->index == NULL) {
45119be09f3SLandon J. Fuller 		/* An index is required for all non-empty, non-root path
45219be09f3SLandon J. Fuller 		 * instances */
45319be09f3SLandon J. Fuller 		BHND_NV_ASSERT(bhnd_nvstore_is_root_path(sc, path),
45419be09f3SLandon J. Fuller 		    ("missing index for non-root path %s", path->path_str));
45519be09f3SLandon J. Fuller 
45619be09f3SLandon J. Fuller 		/* Iterate NVRAM data directly, using the NVRAM data's cookiep
45719be09f3SLandon J. Fuller 		 * value as our indexp context */
45819be09f3SLandon J. Fuller 		if ((bhnd_nvram_data_next(sc->data, indexp)) == NULL)
45919be09f3SLandon J. Fuller 			return (NULL);
46019be09f3SLandon J. Fuller 
46119be09f3SLandon J. Fuller 		return (*indexp);
46219be09f3SLandon J. Fuller 	}
46319be09f3SLandon J. Fuller 
46419be09f3SLandon J. Fuller 	/* Empty index */
46519be09f3SLandon J. Fuller 	if (path->index->count == 0)
46619be09f3SLandon J. Fuller 		return (NULL);
46719be09f3SLandon J. Fuller 
46819be09f3SLandon J. Fuller 	if (*indexp == NULL) {
46919be09f3SLandon J. Fuller 		/* First index entry */
47019be09f3SLandon J. Fuller 		index_ref = &path->index->cookiep[0];
47119be09f3SLandon J. Fuller 	} else {
47219be09f3SLandon J. Fuller 		size_t idxpos;
47319be09f3SLandon J. Fuller 
47419be09f3SLandon J. Fuller 		/* Advance to next index entry */
47519be09f3SLandon J. Fuller 		index_ref = *indexp;
47619be09f3SLandon J. Fuller 		index_ref++;
47719be09f3SLandon J. Fuller 
47819be09f3SLandon J. Fuller 		/* Hit end of index? */
47919be09f3SLandon J. Fuller 		BHND_NV_ASSERT(index_ref > path->index->cookiep,
48019be09f3SLandon J. Fuller 		    ("invalid indexp"));
48119be09f3SLandon J. Fuller 
48219be09f3SLandon J. Fuller 		idxpos = (index_ref - path->index->cookiep);
48319be09f3SLandon J. Fuller 		if (idxpos >= path->index->count)
48419be09f3SLandon J. Fuller 			return (NULL);
48519be09f3SLandon J. Fuller 	}
48619be09f3SLandon J. Fuller 
48719be09f3SLandon J. Fuller 	/* Provide new index position */
48819be09f3SLandon J. Fuller 	*indexp = index_ref;
48919be09f3SLandon J. Fuller 
49019be09f3SLandon J. Fuller 	/* Return the data's cookiep value */
49119be09f3SLandon J. Fuller 	return (*index_ref);
49219be09f3SLandon J. Fuller }
49319be09f3SLandon J. Fuller 
49419be09f3SLandon J. Fuller /**
49519be09f3SLandon J. Fuller  * Perform an lookup of @p name in the backing NVRAM data for @p path,
49619be09f3SLandon J. Fuller  * returning the associated cookiep value, or NULL if the variable is not found
49719be09f3SLandon J. Fuller  * in the backing NVRAM data.
49819be09f3SLandon J. Fuller  *
49919be09f3SLandon J. Fuller  * @warning Pending updates in @p path are ignored by this function.
50019be09f3SLandon J. Fuller  *
50119be09f3SLandon J. Fuller  * @param	sc	The NVRAM store from which NVRAM values will be queried.
50219be09f3SLandon J. Fuller  * @param	path	The path to be queried.
50319be09f3SLandon J. Fuller  * @param	name	The variable name to be queried.
50419be09f3SLandon J. Fuller  *
50519be09f3SLandon J. Fuller  * @retval non-NULL	success
50619be09f3SLandon J. Fuller  * @retval NULL		if @p name is not found in @p index.
50719be09f3SLandon J. Fuller  */
50819be09f3SLandon J. Fuller void *
bhnd_nvstore_path_data_lookup(struct bhnd_nvram_store * sc,bhnd_nvstore_path * path,const char * name)50919be09f3SLandon J. Fuller bhnd_nvstore_path_data_lookup(struct bhnd_nvram_store *sc,
51019be09f3SLandon J. Fuller     bhnd_nvstore_path *path, const char *name)
51119be09f3SLandon J. Fuller {
51219be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
51319be09f3SLandon J. Fuller 
51419be09f3SLandon J. Fuller 	/* No index */
51519be09f3SLandon J. Fuller 	if (path->index == NULL) {
51619be09f3SLandon J. Fuller 		/* An index is required for all non-empty, non-root path
51719be09f3SLandon J. Fuller 		 * instances */
51819be09f3SLandon J. Fuller 		BHND_NV_ASSERT(bhnd_nvstore_is_root_path(sc, path),
51919be09f3SLandon J. Fuller 		    ("missing index for non-root path %s", path->path_str));
52019be09f3SLandon J. Fuller 
52119be09f3SLandon J. Fuller 		/* Look up directly in NVRAM data */
52219be09f3SLandon J. Fuller 		return (bhnd_nvram_data_find(sc->data, name));
52319be09f3SLandon J. Fuller 	}
52419be09f3SLandon J. Fuller 
52519be09f3SLandon J. Fuller 	/* Otherwise, delegate to an index-based lookup */
52619be09f3SLandon J. Fuller 	return (bhnd_nvstore_index_lookup(sc, path->index, name));
52719be09f3SLandon J. Fuller }
52819be09f3SLandon J. Fuller 
52919be09f3SLandon J. Fuller /**
53019be09f3SLandon J. Fuller  * Perform an index lookup of @p name, returning the associated cookiep
53119be09f3SLandon J. Fuller  * value, or NULL if the variable does not exist.
53219be09f3SLandon J. Fuller  *
53319be09f3SLandon J. Fuller  * @param	sc	The NVRAM store from which NVRAM values will be queried.
53419be09f3SLandon J. Fuller  * @param	index	The index to be queried.
53519be09f3SLandon J. Fuller  * @param	name	The variable name to be queried.
53619be09f3SLandon J. Fuller  *
53719be09f3SLandon J. Fuller  * @retval non-NULL	success
53819be09f3SLandon J. Fuller  * @retval NULL		if @p name is not found in @p index.
53919be09f3SLandon J. Fuller  */
54019be09f3SLandon J. Fuller void *
bhnd_nvstore_index_lookup(struct bhnd_nvram_store * sc,bhnd_nvstore_index * index,const char * name)54119be09f3SLandon J. Fuller bhnd_nvstore_index_lookup(struct bhnd_nvram_store *sc,
54219be09f3SLandon J. Fuller     bhnd_nvstore_index *index, const char *name)
54319be09f3SLandon J. Fuller {
54419be09f3SLandon J. Fuller 	void		*cookiep;
54519be09f3SLandon J. Fuller 	const char	*indexed_name;
54619be09f3SLandon J. Fuller 	size_t		 min, mid, max;
54719be09f3SLandon J. Fuller 	uint32_t	 data_caps;
54819be09f3SLandon J. Fuller 	int		 order;
54919be09f3SLandon J. Fuller 
55019be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
55119be09f3SLandon J. Fuller 	BHND_NV_ASSERT(index != NULL, ("NULL index"));
55219be09f3SLandon J. Fuller 
55319be09f3SLandon J. Fuller 	/*
55419be09f3SLandon J. Fuller 	 * Locate the requested variable using a binary search.
55519be09f3SLandon J. Fuller 	 */
55619be09f3SLandon J. Fuller 	if (index->count == 0)
55719be09f3SLandon J. Fuller 		return (NULL);
55819be09f3SLandon J. Fuller 
55919be09f3SLandon J. Fuller 	data_caps = sc->data_caps;
56019be09f3SLandon J. Fuller 	min = 0;
56119be09f3SLandon J. Fuller 	max = index->count - 1;
56219be09f3SLandon J. Fuller 
56319be09f3SLandon J. Fuller 	while (max >= min) {
56419be09f3SLandon J. Fuller 		/* Select midpoint */
56519be09f3SLandon J. Fuller 		mid = (min + max) / 2;
56619be09f3SLandon J. Fuller 		cookiep = index->cookiep[mid];
56719be09f3SLandon J. Fuller 
56819be09f3SLandon J. Fuller 		/* Fetch variable name */
56919be09f3SLandon J. Fuller 		indexed_name = bhnd_nvram_data_getvar_name(sc->data, cookiep);
57019be09f3SLandon J. Fuller 
57119be09f3SLandon J. Fuller 		/* Trim any path prefix */
57219be09f3SLandon J. Fuller 		if (data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS)
57319be09f3SLandon J. Fuller 			indexed_name = bhnd_nvram_trim_path_name(indexed_name);
57419be09f3SLandon J. Fuller 
57519be09f3SLandon J. Fuller 		/* Determine which side of the partition to search */
57619be09f3SLandon J. Fuller 		order = strcmp(indexed_name, name);
57719be09f3SLandon J. Fuller 		if (order < 0) {
57819be09f3SLandon J. Fuller 			/* Search upper partition */
57919be09f3SLandon J. Fuller 			min = mid + 1;
58019be09f3SLandon J. Fuller 		} else if (order > 0) {
58119be09f3SLandon J. Fuller 			/* Search (non-empty) lower partition */
58219be09f3SLandon J. Fuller 			if (mid == 0)
58319be09f3SLandon J. Fuller 				break;
58419be09f3SLandon J. Fuller 			max = mid - 1;
58519be09f3SLandon J. Fuller 		} else if (order == 0) {
58619be09f3SLandon J. Fuller 			size_t	idx;
58719be09f3SLandon J. Fuller 
58819be09f3SLandon J. Fuller 			/*
58919be09f3SLandon J. Fuller 			 * Match found.
59019be09f3SLandon J. Fuller 			 *
59119be09f3SLandon J. Fuller 			 * If this happens to be a key with multiple definitions
59219be09f3SLandon J. Fuller 			 * in the backing store, we need to find the entry with
59319be09f3SLandon J. Fuller 			 * the highest declaration precedence.
59419be09f3SLandon J. Fuller 			 *
59519be09f3SLandon J. Fuller 			 * Duplicates are sorted in order of descending
59619be09f3SLandon J. Fuller 			 * precedence; to find the highest precedence entry,
59719be09f3SLandon J. Fuller 			 * we search backwards through the index.
59819be09f3SLandon J. Fuller 			 */
59919be09f3SLandon J. Fuller 			idx = mid;
60019be09f3SLandon J. Fuller 			while (idx > 0) {
60119be09f3SLandon J. Fuller 				void		*dup_cookiep;
60219be09f3SLandon J. Fuller 				const char	*dup_name;
60319be09f3SLandon J. Fuller 
60419be09f3SLandon J. Fuller 				/* Fetch preceding index entry */
60519be09f3SLandon J. Fuller 				idx--;
60619be09f3SLandon J. Fuller 				dup_cookiep = index->cookiep[idx];
60719be09f3SLandon J. Fuller 				dup_name = bhnd_nvram_data_getvar_name(sc->data,
60819be09f3SLandon J. Fuller 				    dup_cookiep);
60919be09f3SLandon J. Fuller 
61019be09f3SLandon J. Fuller 				/* Trim any path prefix */
61119be09f3SLandon J. Fuller 				if (data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS) {
61219be09f3SLandon J. Fuller 					dup_name = bhnd_nvram_trim_path_name(
61319be09f3SLandon J. Fuller 					    dup_name);
61419be09f3SLandon J. Fuller 				}
61519be09f3SLandon J. Fuller 
61619be09f3SLandon J. Fuller 				/* If no match, current cookiep is the variable
61719be09f3SLandon J. Fuller 				 * definition with the highest precedence */
61819be09f3SLandon J. Fuller 				if (strcmp(indexed_name, dup_name) != 0)
61919be09f3SLandon J. Fuller 					return (cookiep);
62019be09f3SLandon J. Fuller 
62119be09f3SLandon J. Fuller 				/* Otherwise, prefer this earlier definition,
62219be09f3SLandon J. Fuller 				 * and keep searching for a higher-precedence
62319be09f3SLandon J. Fuller 				 * definitions */
62419be09f3SLandon J. Fuller 				cookiep = dup_cookiep;
62519be09f3SLandon J. Fuller 			}
62619be09f3SLandon J. Fuller 
62719be09f3SLandon J. Fuller 			return (cookiep);
62819be09f3SLandon J. Fuller 		}
62919be09f3SLandon J. Fuller 	}
63019be09f3SLandon J. Fuller 
63119be09f3SLandon J. Fuller 	/* Not found */
63219be09f3SLandon J. Fuller 	return (NULL);
63319be09f3SLandon J. Fuller }
63419be09f3SLandon J. Fuller 
63519be09f3SLandon J. Fuller /**
63619be09f3SLandon J. Fuller  * Return the device path entry registered for @p path, if any.
63719be09f3SLandon J. Fuller  *
63819be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be queried.
63919be09f3SLandon J. Fuller  * @param	path		The device path to search for.
64019be09f3SLandon J. Fuller  * @param	path_len	The length of @p path.
64119be09f3SLandon J. Fuller  *
64219be09f3SLandon J. Fuller  * @retval non-NULL	if found.
64319be09f3SLandon J. Fuller  * @retval NULL		if not found.
64419be09f3SLandon J. Fuller  */
64519be09f3SLandon J. Fuller bhnd_nvstore_path *
bhnd_nvstore_get_path(struct bhnd_nvram_store * sc,const char * path,size_t path_len)64619be09f3SLandon J. Fuller bhnd_nvstore_get_path(struct bhnd_nvram_store *sc, const char *path,
64719be09f3SLandon J. Fuller     size_t path_len)
64819be09f3SLandon J. Fuller {
64919be09f3SLandon J. Fuller 	bhnd_nvstore_path_list	*plist;
65019be09f3SLandon J. Fuller 	bhnd_nvstore_path	*p;
65119be09f3SLandon J. Fuller 	uint32_t		 h;
65219be09f3SLandon J. Fuller 
65319be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
65419be09f3SLandon J. Fuller 
65519be09f3SLandon J. Fuller 	/* Use hash lookup */
65619be09f3SLandon J. Fuller 	h = hash32_strn(path, path_len, HASHINIT);
65719be09f3SLandon J. Fuller 	plist = &sc->paths[h % nitems(sc->paths)];
65819be09f3SLandon J. Fuller 
65919be09f3SLandon J. Fuller 	LIST_FOREACH(p, plist, np_link) {
66019be09f3SLandon J. Fuller 		/* Check for prefix match */
66119be09f3SLandon J. Fuller 		if (strncmp(p->path_str, path, path_len) != 0)
66219be09f3SLandon J. Fuller 			continue;
66319be09f3SLandon J. Fuller 
66419be09f3SLandon J. Fuller 		/* Check for complete match */
66519be09f3SLandon J. Fuller 		if (strnlen(path, path_len) != strlen(p->path_str))
66619be09f3SLandon J. Fuller 			continue;
66719be09f3SLandon J. Fuller 
66819be09f3SLandon J. Fuller 		return (p);
66919be09f3SLandon J. Fuller 	}
67019be09f3SLandon J. Fuller 
67119be09f3SLandon J. Fuller 	/* Not found */
67219be09f3SLandon J. Fuller 	return (NULL);
67319be09f3SLandon J. Fuller }
67419be09f3SLandon J. Fuller 
67519be09f3SLandon J. Fuller /**
67619be09f3SLandon J. Fuller  * Resolve @p aval to its corresponding device path entry, if any.
67719be09f3SLandon J. Fuller  *
67819be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be queried.
67919be09f3SLandon J. Fuller  * @param	aval		The device path alias value to search for.
68019be09f3SLandon J. Fuller  *
68119be09f3SLandon J. Fuller  * @retval non-NULL	if found.
68219be09f3SLandon J. Fuller  * @retval NULL		if not found.
68319be09f3SLandon J. Fuller  */
68419be09f3SLandon J. Fuller bhnd_nvstore_path *
bhnd_nvstore_resolve_path_alias(struct bhnd_nvram_store * sc,u_long aval)68519be09f3SLandon J. Fuller bhnd_nvstore_resolve_path_alias(struct bhnd_nvram_store *sc, u_long aval)
68619be09f3SLandon J. Fuller {
68719be09f3SLandon J. Fuller 	bhnd_nvstore_alias *alias;
68819be09f3SLandon J. Fuller 
68919be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
69019be09f3SLandon J. Fuller 
69119be09f3SLandon J. Fuller 	/* Fetch alias entry */
69219be09f3SLandon J. Fuller 	if ((alias = bhnd_nvstore_get_alias(sc, aval)) == NULL)
69319be09f3SLandon J. Fuller 		return (NULL);
69419be09f3SLandon J. Fuller 
69519be09f3SLandon J. Fuller 	return (alias->path);
69619be09f3SLandon J. Fuller }
69719be09f3SLandon J. Fuller 
69819be09f3SLandon J. Fuller /**
69919be09f3SLandon J. Fuller  * Register a device path entry for the path referenced by variable name
70019be09f3SLandon J. Fuller  * @p info, if any.
70119be09f3SLandon J. Fuller  *
70219be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be updated.
70319be09f3SLandon J. Fuller  * @param	info		The NVRAM variable name info.
70419be09f3SLandon J. Fuller  * @param	cookiep		The NVRAM variable's cookiep value.
70519be09f3SLandon J. Fuller  *
70619be09f3SLandon J. Fuller  * @retval 0		if the path was successfully registered, or an identical
70719be09f3SLandon J. Fuller  *			path or alias entry exists.
70819be09f3SLandon J. Fuller  * @retval EEXIST	if a conflicting entry already exists for the path or
70919be09f3SLandon J. Fuller  *			alias referenced by @p info.
71019be09f3SLandon J. Fuller  * @retval ENOENT	if @p info contains a dangling alias reference.
71119be09f3SLandon J. Fuller  * @retval EINVAL	if @p info contains an unsupported bhnd_nvstore_var_type
71219be09f3SLandon J. Fuller  *			and bhnd_nvstore_path_type combination.
71319be09f3SLandon J. Fuller  * @retval ENOMEM	if allocation fails.
71419be09f3SLandon J. Fuller  */
71519be09f3SLandon J. Fuller int
bhnd_nvstore_var_register_path(struct bhnd_nvram_store * sc,bhnd_nvstore_name_info * info,void * cookiep)71619be09f3SLandon J. Fuller bhnd_nvstore_var_register_path(struct bhnd_nvram_store *sc,
71719be09f3SLandon J. Fuller     bhnd_nvstore_name_info *info, void *cookiep)
71819be09f3SLandon J. Fuller {
71919be09f3SLandon J. Fuller 	switch (info->type) {
72019be09f3SLandon J. Fuller 	case BHND_NVSTORE_VAR:
72119be09f3SLandon J. Fuller 		/* Variable */
72219be09f3SLandon J. Fuller 		switch (info->path_type) {
72319be09f3SLandon J. Fuller 		case BHND_NVSTORE_PATH_STRING:
72419be09f3SLandon J. Fuller 			/* Variable contains a full path string
72519be09f3SLandon J. Fuller 			 * (pci/1/1/varname); register the path */
72619be09f3SLandon J. Fuller 			return (bhnd_nvstore_register_path(sc,
72719be09f3SLandon J. Fuller 			    info->path.str.value, info->path.str.value_len));
72819be09f3SLandon J. Fuller 
72919be09f3SLandon J. Fuller 		case BHND_NVSTORE_PATH_ALIAS:
73019be09f3SLandon J. Fuller 			/* Variable contains an alias reference (0:varname).
73119be09f3SLandon J. Fuller 			 * There's no path to register */
73219be09f3SLandon J. Fuller 			return (0);
73319be09f3SLandon J. Fuller 		}
73419be09f3SLandon J. Fuller 
73519be09f3SLandon J. Fuller 		BHND_NV_PANIC("unsupported path type %d", info->path_type);
73619be09f3SLandon J. Fuller 		break;
73719be09f3SLandon J. Fuller 
73819be09f3SLandon J. Fuller 	case BHND_NVSTORE_ALIAS_DECL:
73919be09f3SLandon J. Fuller 		/* Alias declaration */
74019be09f3SLandon J. Fuller 		return (bhnd_nvstore_register_alias(sc, info, cookiep));
74119be09f3SLandon J. Fuller 	}
74219be09f3SLandon J. Fuller 
74319be09f3SLandon J. Fuller 	BHND_NV_PANIC("unsupported var type %d", info->type);
74419be09f3SLandon J. Fuller }
74519be09f3SLandon J. Fuller 
74619be09f3SLandon J. Fuller /**
747caa7e52fSEitan Adler  * Resolve the device path entry referenced by @p info.
74819be09f3SLandon J. Fuller  *
74919be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be updated.
75019be09f3SLandon J. Fuller  * @param	info		Variable name information descriptor containing
75119be09f3SLandon J. Fuller  *				the path or path alias to be resolved.
75219be09f3SLandon J. Fuller  *
75319be09f3SLandon J. Fuller  * @retval non-NULL	if found.
75419be09f3SLandon J. Fuller  * @retval NULL		if not found.
75519be09f3SLandon J. Fuller  */
75619be09f3SLandon J. Fuller bhnd_nvstore_path *
bhnd_nvstore_var_get_path(struct bhnd_nvram_store * sc,bhnd_nvstore_name_info * info)75719be09f3SLandon J. Fuller bhnd_nvstore_var_get_path(struct bhnd_nvram_store *sc,
75819be09f3SLandon J. Fuller     bhnd_nvstore_name_info *info)
75919be09f3SLandon J. Fuller {
76019be09f3SLandon J. Fuller 	switch (info->path_type) {
76119be09f3SLandon J. Fuller 	case BHND_NVSTORE_PATH_STRING:
76219be09f3SLandon J. Fuller 		return (bhnd_nvstore_get_path(sc, info->path.str.value,
76319be09f3SLandon J. Fuller 		    info->path.str.value_len));
76419be09f3SLandon J. Fuller 	case BHND_NVSTORE_PATH_ALIAS:
76519be09f3SLandon J. Fuller 		return (bhnd_nvstore_resolve_path_alias(sc,
76619be09f3SLandon J. Fuller 		    info->path.alias.value));
76719be09f3SLandon J. Fuller 	}
76819be09f3SLandon J. Fuller 
76919be09f3SLandon J. Fuller 	BHND_NV_PANIC("unsupported path type %d", info->path_type);
77019be09f3SLandon J. Fuller }
77119be09f3SLandon J. Fuller 
77219be09f3SLandon J. Fuller /**
77319be09f3SLandon J. Fuller  * Return the device path alias entry registered for @p alias_val, if any.
77419be09f3SLandon J. Fuller  *
77519be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be queried.
77619be09f3SLandon J. Fuller  * @param	alias_val	The alias value to search for.
77719be09f3SLandon J. Fuller  *
77819be09f3SLandon J. Fuller  * @retval non-NULL	if found.
77919be09f3SLandon J. Fuller  * @retval NULL		if not found.
78019be09f3SLandon J. Fuller  */
78119be09f3SLandon J. Fuller bhnd_nvstore_alias *
bhnd_nvstore_get_alias(struct bhnd_nvram_store * sc,u_long alias_val)78219be09f3SLandon J. Fuller bhnd_nvstore_get_alias(struct bhnd_nvram_store *sc, u_long alias_val)
78319be09f3SLandon J. Fuller {
78419be09f3SLandon J. Fuller 	bhnd_nvstore_alias_list	*alist;
78519be09f3SLandon J. Fuller 	bhnd_nvstore_alias	*alias;
78619be09f3SLandon J. Fuller 
78719be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
78819be09f3SLandon J. Fuller 
78919be09f3SLandon J. Fuller 	/* Can use hash lookup */
79019be09f3SLandon J. Fuller 	alist = &sc->aliases[alias_val % nitems(sc->aliases)];
79119be09f3SLandon J. Fuller 	LIST_FOREACH(alias, alist, na_link) {
79219be09f3SLandon J. Fuller 		if (alias->alias == alias_val)
79319be09f3SLandon J. Fuller 			return (alias);
79419be09f3SLandon J. Fuller 	}
79519be09f3SLandon J. Fuller 
79619be09f3SLandon J. Fuller 	/* Not found */
79719be09f3SLandon J. Fuller 	return (NULL);
79819be09f3SLandon J. Fuller }
79919be09f3SLandon J. Fuller 
80019be09f3SLandon J. Fuller /**
80119be09f3SLandon J. Fuller  * Return the device path alias entry registered for @p path, if any.
80219be09f3SLandon J. Fuller  *
80319be09f3SLandon J. Fuller  * @param	sc	The NVRAM store to be queried.
80419be09f3SLandon J. Fuller  * @param	path	The alias path to search for.
80519be09f3SLandon J. Fuller  *
80619be09f3SLandon J. Fuller  * @retval non-NULL	if found.
80719be09f3SLandon J. Fuller  * @retval NULL		if not found.
80819be09f3SLandon J. Fuller  */
80919be09f3SLandon J. Fuller bhnd_nvstore_alias *
bhnd_nvstore_find_alias(struct bhnd_nvram_store * sc,const char * path)81019be09f3SLandon J. Fuller bhnd_nvstore_find_alias(struct bhnd_nvram_store *sc, const char *path)
81119be09f3SLandon J. Fuller {
81219be09f3SLandon J. Fuller 	bhnd_nvstore_alias *alias;
81319be09f3SLandon J. Fuller 
81419be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
81519be09f3SLandon J. Fuller 
81619be09f3SLandon J. Fuller 	/* Have to scan the full table */
81719be09f3SLandon J. Fuller 	for (size_t i = 0; i < nitems(sc->aliases); i++) {
81819be09f3SLandon J. Fuller 		LIST_FOREACH(alias, &sc->aliases[i], na_link) {
81919be09f3SLandon J. Fuller 			if (strcmp(alias->path->path_str, path) == 0)
82019be09f3SLandon J. Fuller 				return (alias);
82119be09f3SLandon J. Fuller 		}
82219be09f3SLandon J. Fuller 	}
82319be09f3SLandon J. Fuller 
82419be09f3SLandon J. Fuller 	/* Not found */
82519be09f3SLandon J. Fuller 	return (NULL);
82619be09f3SLandon J. Fuller }
82719be09f3SLandon J. Fuller 
82819be09f3SLandon J. Fuller /**
82919be09f3SLandon J. Fuller  * Register a device path entry for @p path.
83019be09f3SLandon J. Fuller  *
83119be09f3SLandon J. Fuller  * @param	sc		The NVRAM store to be updated.
83219be09f3SLandon J. Fuller  * @param	path_str	The absolute device path string.
83319be09f3SLandon J. Fuller  * @param	path_len	The length of @p path_str.
83419be09f3SLandon J. Fuller  *
83519be09f3SLandon J. Fuller  * @retval 0		if the path was successfully registered, or an identical
83619be09f3SLandon J. Fuller  *			path/alias entry already exists.
83719be09f3SLandon J. Fuller  * @retval ENOMEM	if allocation fails.
83819be09f3SLandon J. Fuller  */
83919be09f3SLandon J. Fuller int
bhnd_nvstore_register_path(struct bhnd_nvram_store * sc,const char * path_str,size_t path_len)84019be09f3SLandon J. Fuller bhnd_nvstore_register_path(struct bhnd_nvram_store *sc, const char *path_str,
84119be09f3SLandon J. Fuller     size_t path_len)
84219be09f3SLandon J. Fuller {
84319be09f3SLandon J. Fuller 	bhnd_nvstore_path_list	*plist;
84419be09f3SLandon J. Fuller 	bhnd_nvstore_path	*path;
84519be09f3SLandon J. Fuller 	uint32_t		 h;
84619be09f3SLandon J. Fuller 
84719be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
84819be09f3SLandon J. Fuller 
84919be09f3SLandon J. Fuller 	/* Already exists? */
85019be09f3SLandon J. Fuller 	if (bhnd_nvstore_get_path(sc, path_str, path_len) != NULL)
85119be09f3SLandon J. Fuller 		return (0);
85219be09f3SLandon J. Fuller 
85319be09f3SLandon J. Fuller 	/* Can't represent more than SIZE_MAX paths */
85419be09f3SLandon J. Fuller 	if (sc->num_paths == SIZE_MAX)
85519be09f3SLandon J. Fuller 		return (ENOMEM);
85619be09f3SLandon J. Fuller 
85719be09f3SLandon J. Fuller 	/* Allocate new entry */
85819be09f3SLandon J. Fuller 	path = bhnd_nvstore_path_new(path_str, path_len);
85919be09f3SLandon J. Fuller 	if (path == NULL)
86019be09f3SLandon J. Fuller 		return (ENOMEM);
86119be09f3SLandon J. Fuller 
86219be09f3SLandon J. Fuller 	/* Insert in path hash table */
86319be09f3SLandon J. Fuller 	h = hash32_str(path->path_str, HASHINIT);
86419be09f3SLandon J. Fuller 	plist = &sc->paths[h % nitems(sc->paths)];
86519be09f3SLandon J. Fuller 	LIST_INSERT_HEAD(plist, path, np_link);
86619be09f3SLandon J. Fuller 
86719be09f3SLandon J. Fuller 	/* Increment path count */
86819be09f3SLandon J. Fuller 	sc->num_paths++;
86919be09f3SLandon J. Fuller 
87019be09f3SLandon J. Fuller 	return (0);
87119be09f3SLandon J. Fuller }
87219be09f3SLandon J. Fuller 
87319be09f3SLandon J. Fuller /**
87419be09f3SLandon J. Fuller  * Register a device path alias for an NVRAM 'devpathX' variable.
87519be09f3SLandon J. Fuller  *
87619be09f3SLandon J. Fuller  * The path value for the alias will be fetched from the backing NVRAM data.
87719be09f3SLandon J. Fuller  *
87819be09f3SLandon J. Fuller  * @param	sc	The NVRAM store to be updated.
87919be09f3SLandon J. Fuller  * @param	info	The NVRAM variable name info.
88019be09f3SLandon J. Fuller  * @param	cookiep	The NVRAM variable's cookiep value.
88119be09f3SLandon J. Fuller  *
88219be09f3SLandon J. Fuller  * @retval 0		if the alias was successfully registered, or an
88319be09f3SLandon J. Fuller  *			identical alias entry exists.
88419be09f3SLandon J. Fuller  * @retval EEXIST	if a conflicting alias or path entry already exists.
88519be09f3SLandon J. Fuller  * @retval EINVAL	if @p info is not a BHND_NVSTORE_ALIAS_DECL or does
88619be09f3SLandon J. Fuller  *			not contain a BHND_NVSTORE_PATH_ALIAS entry.
88719be09f3SLandon J. Fuller  * @retval ENOMEM	if allocation fails.
88819be09f3SLandon J. Fuller  */
88919be09f3SLandon J. Fuller int
bhnd_nvstore_register_alias(struct bhnd_nvram_store * sc,const bhnd_nvstore_name_info * info,void * cookiep)89019be09f3SLandon J. Fuller bhnd_nvstore_register_alias(struct bhnd_nvram_store *sc,
89119be09f3SLandon J. Fuller     const bhnd_nvstore_name_info *info, void *cookiep)
89219be09f3SLandon J. Fuller {
89319be09f3SLandon J. Fuller 	bhnd_nvstore_alias_list	*alist;
89419be09f3SLandon J. Fuller 	bhnd_nvstore_alias	*alias;
89519be09f3SLandon J. Fuller 	bhnd_nvstore_path	*path;
89619be09f3SLandon J. Fuller 	char			*path_str;
89719be09f3SLandon J. Fuller 	size_t			 path_len;
89819be09f3SLandon J. Fuller 	int			 error;
89919be09f3SLandon J. Fuller 
90019be09f3SLandon J. Fuller 	BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED);
90119be09f3SLandon J. Fuller 
90219be09f3SLandon J. Fuller 	path_str = NULL;
90319be09f3SLandon J. Fuller 	alias = NULL;
90419be09f3SLandon J. Fuller 
90519be09f3SLandon J. Fuller 	/* Can't represent more than SIZE_MAX aliases */
90619be09f3SLandon J. Fuller 	if (sc->num_aliases == SIZE_MAX)
90719be09f3SLandon J. Fuller 		return (ENOMEM);
90819be09f3SLandon J. Fuller 
90919be09f3SLandon J. Fuller 	/* Must be an alias declaration */
91019be09f3SLandon J. Fuller 	if (info->type != BHND_NVSTORE_ALIAS_DECL)
91119be09f3SLandon J. Fuller 		return (EINVAL);
91219be09f3SLandon J. Fuller 
91319be09f3SLandon J. Fuller 	if (info->path_type != BHND_NVSTORE_PATH_ALIAS)
91419be09f3SLandon J. Fuller 		return (EINVAL);
91519be09f3SLandon J. Fuller 
91619be09f3SLandon J. Fuller 	/* Fetch the devpath variable's value length */
91719be09f3SLandon J. Fuller 	error = bhnd_nvram_data_getvar(sc->data, cookiep, NULL, &path_len,
91819be09f3SLandon J. Fuller 	    BHND_NVRAM_TYPE_STRING);
91919be09f3SLandon J. Fuller 	if (error)
92019be09f3SLandon J. Fuller 		return (ENOMEM);
92119be09f3SLandon J. Fuller 
92219be09f3SLandon J. Fuller 	/* Allocate path string buffer */
92319be09f3SLandon J. Fuller 	if ((path_str = bhnd_nv_malloc(path_len)) == NULL)
92419be09f3SLandon J. Fuller 		return (ENOMEM);
92519be09f3SLandon J. Fuller 
92619be09f3SLandon J. Fuller 	/* Decode to our new buffer */
92719be09f3SLandon J. Fuller 	error = bhnd_nvram_data_getvar(sc->data, cookiep, path_str, &path_len,
92819be09f3SLandon J. Fuller 	    BHND_NVRAM_TYPE_STRING);
92919be09f3SLandon J. Fuller 	if (error)
93019be09f3SLandon J. Fuller 		goto failed;
93119be09f3SLandon J. Fuller 
93219be09f3SLandon J. Fuller 	/* Trim trailing '/' character(s) from the path length */
93319be09f3SLandon J. Fuller 	path_len = strnlen(path_str, path_len);
93419be09f3SLandon J. Fuller 	while (path_len > 0 && path_str[path_len-1] == '/') {
93519be09f3SLandon J. Fuller 		path_str[path_len-1] = '\0';
93619be09f3SLandon J. Fuller 		path_len--;
93719be09f3SLandon J. Fuller 	}
93819be09f3SLandon J. Fuller 
93919be09f3SLandon J. Fuller 	/* Is a conflicting alias entry already registered for this alias
94019be09f3SLandon J. Fuller 	 * value? */
94119be09f3SLandon J. Fuller 	alias = bhnd_nvstore_get_alias(sc, info->path.alias.value);
94219be09f3SLandon J. Fuller 	if (alias != NULL) {
94319be09f3SLandon J. Fuller 		if (alias->cookiep != cookiep ||
94419be09f3SLandon J. Fuller 		    strcmp(alias->path->path_str, path_str) != 0)
94519be09f3SLandon J. Fuller 		{
94619be09f3SLandon J. Fuller 			error = EEXIST;
94719be09f3SLandon J. Fuller 			goto failed;
94819be09f3SLandon J. Fuller 		}
94919be09f3SLandon J. Fuller 	}
95019be09f3SLandon J. Fuller 
95119be09f3SLandon J. Fuller 	/* Is a conflicting entry already registered for the alias path? */
95219be09f3SLandon J. Fuller 	if ((alias = bhnd_nvstore_find_alias(sc, path_str)) != NULL) {
95319be09f3SLandon J. Fuller 		if (alias->alias != info->path.alias.value ||
95419be09f3SLandon J. Fuller 		    alias->cookiep != cookiep ||
95519be09f3SLandon J. Fuller 		    strcmp(alias->path->path_str, path_str) != 0)
95619be09f3SLandon J. Fuller 		{
95719be09f3SLandon J. Fuller 			error = EEXIST;
95819be09f3SLandon J. Fuller 			goto failed;
95919be09f3SLandon J. Fuller 		}
96019be09f3SLandon J. Fuller 	}
96119be09f3SLandon J. Fuller 
96219be09f3SLandon J. Fuller 	/* Get (or register) the target path entry */
96319be09f3SLandon J. Fuller 	path = bhnd_nvstore_get_path(sc, path_str, path_len);
96419be09f3SLandon J. Fuller 	if (path == NULL) {
96519be09f3SLandon J. Fuller 		error = bhnd_nvstore_register_path(sc, path_str, path_len);
96619be09f3SLandon J. Fuller 		if (error)
96719be09f3SLandon J. Fuller 			goto failed;
96819be09f3SLandon J. Fuller 
96919be09f3SLandon J. Fuller 		path = bhnd_nvstore_get_path(sc, path_str, path_len);
97019be09f3SLandon J. Fuller 		BHND_NV_ASSERT(path != NULL, ("missing registered path"));
97119be09f3SLandon J. Fuller 	}
97219be09f3SLandon J. Fuller 
97319be09f3SLandon J. Fuller 	/* Allocate alias entry */
97419be09f3SLandon J. Fuller 	alias = bhnd_nv_calloc(1, sizeof(*alias));
97519be09f3SLandon J. Fuller 	if (alias == NULL) {
97619be09f3SLandon J. Fuller 		error = ENOMEM;
97719be09f3SLandon J. Fuller 		goto failed;
97819be09f3SLandon J. Fuller 	}
97919be09f3SLandon J. Fuller 
98019be09f3SLandon J. Fuller 	alias->path = path;
98119be09f3SLandon J. Fuller 	alias->cookiep = cookiep;
98219be09f3SLandon J. Fuller 	alias->alias = info->path.alias.value;
98319be09f3SLandon J. Fuller 
98419be09f3SLandon J. Fuller 	/* Insert in alias hash table */
98519be09f3SLandon J. Fuller 	alist = &sc->aliases[alias->alias % nitems(sc->aliases)];
98619be09f3SLandon J. Fuller 	LIST_INSERT_HEAD(alist, alias, na_link);
98719be09f3SLandon J. Fuller 
98819be09f3SLandon J. Fuller 	/* Increment alias count */
98919be09f3SLandon J. Fuller 	sc->num_aliases++;
99019be09f3SLandon J. Fuller 
99119be09f3SLandon J. Fuller 	bhnd_nv_free(path_str);
99219be09f3SLandon J. Fuller 	return (0);
99319be09f3SLandon J. Fuller 
99419be09f3SLandon J. Fuller failed:
99519be09f3SLandon J. Fuller 	if (path_str != NULL)
99619be09f3SLandon J. Fuller 		bhnd_nv_free(path_str);
99719be09f3SLandon J. Fuller 
99819be09f3SLandon J. Fuller 	if (alias != NULL)
99919be09f3SLandon J. Fuller 		bhnd_nv_free(alias);
100019be09f3SLandon J. Fuller 
100119be09f3SLandon J. Fuller 	return (error);
100219be09f3SLandon J. Fuller }
100319be09f3SLandon J. Fuller 
100419be09f3SLandon J. Fuller /**
100519be09f3SLandon J. Fuller  * If @p child is equal to or a child path of @p parent, return a pointer to
100619be09f3SLandon J. Fuller  * @p child's path component(s) relative to @p parent; otherwise, return NULL.
100719be09f3SLandon J. Fuller  */
100819be09f3SLandon J. Fuller const char *
bhnd_nvstore_parse_relpath(const char * parent,const char * child)100919be09f3SLandon J. Fuller bhnd_nvstore_parse_relpath(const char *parent, const char *child)
101019be09f3SLandon J. Fuller {
101119be09f3SLandon J. Fuller 	size_t prefix_len;
101219be09f3SLandon J. Fuller 
101319be09f3SLandon J. Fuller 	/* All paths have an implicit leading '/'; this allows us to treat
101419be09f3SLandon J. Fuller 	 * our manufactured root path of "/" as a prefix to all NVRAM-defined
101519be09f3SLandon J. Fuller 	 * paths (which do not necessarily include a leading '/' */
101619be09f3SLandon J. Fuller 	if (*parent == '/')
101719be09f3SLandon J. Fuller 		parent++;
101819be09f3SLandon J. Fuller 
101919be09f3SLandon J. Fuller 	if (*child == '/')
102019be09f3SLandon J. Fuller 		child++;
102119be09f3SLandon J. Fuller 
102219be09f3SLandon J. Fuller 	/* Is parent a prefix of child? */
102319be09f3SLandon J. Fuller 	prefix_len = strlen(parent);
102419be09f3SLandon J. Fuller 	if (strncmp(parent, child, prefix_len) != 0)
102519be09f3SLandon J. Fuller 		return (NULL);
102619be09f3SLandon J. Fuller 
102719be09f3SLandon J. Fuller 	/* A zero-length prefix matches everything */
102819be09f3SLandon J. Fuller 	if (prefix_len == 0)
102919be09f3SLandon J. Fuller 		return (child);
103019be09f3SLandon J. Fuller 
103119be09f3SLandon J. Fuller 	/* Is child equal to parent? */
103219be09f3SLandon J. Fuller 	if (child[prefix_len] == '\0')
103319be09f3SLandon J. Fuller 		return (child + prefix_len);
103419be09f3SLandon J. Fuller 
103519be09f3SLandon J. Fuller 	/* Is child actually a child of parent? */
103619be09f3SLandon J. Fuller 	if (child[prefix_len] == '/')
103719be09f3SLandon J. Fuller 		return (child + prefix_len + 1);
103819be09f3SLandon J. Fuller 
103919be09f3SLandon J. Fuller 	/* No match (e.g. parent=/foo..., child=/fooo...) */
104019be09f3SLandon J. Fuller 	return (NULL);
104119be09f3SLandon J. Fuller }
104219be09f3SLandon J. Fuller 
104319be09f3SLandon J. Fuller /**
104419be09f3SLandon J. Fuller  * Parse a raw NVRAM variable name and return its @p entry_type, its
104519be09f3SLandon J. Fuller  * type-specific @p prefix (e.g. '0:', 'pci/1/1', 'devpath'), and its
104619be09f3SLandon J. Fuller  * type-specific @p suffix (e.g. 'varname', '0').
104719be09f3SLandon J. Fuller  *
104819be09f3SLandon J. Fuller  * @param	name		The NVRAM variable name to be parsed. This
104919be09f3SLandon J. Fuller  *				value must remain valid for the lifetime of
105019be09f3SLandon J. Fuller  *				@p info.
105119be09f3SLandon J. Fuller  * @param	type		The NVRAM name type -- either INTERNAL for names
105219be09f3SLandon J. Fuller  *				parsed from backing NVRAM data, or EXTERNAL for
105319be09f3SLandon J. Fuller  *				names provided by external NVRAM store clients.
105419be09f3SLandon J. Fuller  * @param	data_caps	The backing NVRAM data capabilities
105519be09f3SLandon J. Fuller  *				(see bhnd_nvram_data_caps()).
105619be09f3SLandon J. Fuller  * @param[out]	info		On success, the parsed variable name info.
105719be09f3SLandon J. Fuller  *
105819be09f3SLandon J. Fuller  * @retval 0		success
105919be09f3SLandon J. Fuller  * @retval non-zero	if parsing @p name otherwise fails, a regular unix
106019be09f3SLandon J. Fuller  *			error code will be returned.
106119be09f3SLandon J. Fuller  */
106219be09f3SLandon J. Fuller int
bhnd_nvstore_parse_name_info(const char * name,bhnd_nvstore_name_type type,uint32_t data_caps,bhnd_nvstore_name_info * info)106319be09f3SLandon J. Fuller bhnd_nvstore_parse_name_info(const char *name, bhnd_nvstore_name_type type,
106419be09f3SLandon J. Fuller     uint32_t data_caps, bhnd_nvstore_name_info *info)
106519be09f3SLandon J. Fuller {
106619be09f3SLandon J. Fuller 	const char	*p;
106719be09f3SLandon J. Fuller 	char		*endp;
106819be09f3SLandon J. Fuller 
106919be09f3SLandon J. Fuller 	/* Skip path parsing? */
107019be09f3SLandon J. Fuller 	if (data_caps & BHND_NVRAM_DATA_CAP_DEVPATHS) {
107119be09f3SLandon J. Fuller 		/* devpath declaration? (devpath0=pci/1/1) */
107219be09f3SLandon J. Fuller 		if (strncmp(name, "devpath", strlen("devpath")) == 0) {
107319be09f3SLandon J. Fuller 			u_long alias;
107419be09f3SLandon J. Fuller 
107519be09f3SLandon J. Fuller 			/* Perform standard validation on the relative
107619be09f3SLandon J. Fuller 			 * variable name */
107719be09f3SLandon J. Fuller 			if (type != BHND_NVSTORE_NAME_INTERNAL &&
107819be09f3SLandon J. Fuller 			    !bhnd_nvram_validate_name(name))
107919be09f3SLandon J. Fuller 			{
108019be09f3SLandon J. Fuller 				return (ENOENT);
108119be09f3SLandon J. Fuller 			}
108219be09f3SLandon J. Fuller 
108319be09f3SLandon J. Fuller 			/* Parse alias value that should follow a 'devpath'
108419be09f3SLandon J. Fuller 			 * prefix */
108519be09f3SLandon J. Fuller 			p = name + strlen("devpath");
108619be09f3SLandon J. Fuller 			alias = strtoul(p, &endp, 10);
108719be09f3SLandon J. Fuller 			if (endp != p && *endp == '\0') {
108819be09f3SLandon J. Fuller 				info->type = BHND_NVSTORE_ALIAS_DECL;
108919be09f3SLandon J. Fuller 				info->path_type = BHND_NVSTORE_PATH_ALIAS;
109019be09f3SLandon J. Fuller 				info->name = name;
109119be09f3SLandon J. Fuller 				info->path.alias.value = alias;
109219be09f3SLandon J. Fuller 
109319be09f3SLandon J. Fuller 				return (0);
109419be09f3SLandon J. Fuller 			}
109519be09f3SLandon J. Fuller 		}
109619be09f3SLandon J. Fuller 
109719be09f3SLandon J. Fuller 		/* device aliased variable? (0:varname) */
109819be09f3SLandon J. Fuller 		if (bhnd_nv_isdigit(*name)) {
109919be09f3SLandon J. Fuller 			u_long alias;
110019be09f3SLandon J. Fuller 
110119be09f3SLandon J. Fuller 			/* Parse '0:' alias prefix */
110219be09f3SLandon J. Fuller 			alias = strtoul(name, &endp, 10);
110319be09f3SLandon J. Fuller 			if (endp != name && *endp == ':') {
110419be09f3SLandon J. Fuller 				/* Perform standard validation on the relative
110519be09f3SLandon J. Fuller 				 * variable name */
110619be09f3SLandon J. Fuller 				if (type != BHND_NVSTORE_NAME_INTERNAL &&
110719be09f3SLandon J. Fuller 				    !bhnd_nvram_validate_name(name))
110819be09f3SLandon J. Fuller 				{
110919be09f3SLandon J. Fuller 					return (ENOENT);
111019be09f3SLandon J. Fuller 				}
111119be09f3SLandon J. Fuller 
111219be09f3SLandon J. Fuller 				info->type = BHND_NVSTORE_VAR;
111319be09f3SLandon J. Fuller 				info->path_type = BHND_NVSTORE_PATH_ALIAS;
111419be09f3SLandon J. Fuller 
111519be09f3SLandon J. Fuller 				/* name follows 0: prefix */
111619be09f3SLandon J. Fuller 				info->name = endp + 1;
111719be09f3SLandon J. Fuller 				info->path.alias.value = alias;
111819be09f3SLandon J. Fuller 
111919be09f3SLandon J. Fuller 				return (0);
112019be09f3SLandon J. Fuller 			}
112119be09f3SLandon J. Fuller 		}
112219be09f3SLandon J. Fuller 
112319be09f3SLandon J. Fuller 		/* device variable? (pci/1/1/varname) */
112419be09f3SLandon J. Fuller 		if ((p = strrchr(name, '/')) != NULL) {
112519be09f3SLandon J. Fuller 			const char	*path, *relative_name;
112619be09f3SLandon J. Fuller 			size_t		 path_len;
112719be09f3SLandon J. Fuller 
112819be09f3SLandon J. Fuller 			/* Determine the path length; 'p' points at the last
112919be09f3SLandon J. Fuller 			 * path separator in 'name' */
113019be09f3SLandon J. Fuller 			path_len = p - name;
113119be09f3SLandon J. Fuller 			path = name;
113219be09f3SLandon J. Fuller 
113319be09f3SLandon J. Fuller 			/* The relative variable name directly follows the
113419be09f3SLandon J. Fuller 			 * final path separator '/' */
113519be09f3SLandon J. Fuller 			relative_name = path + path_len + 1;
113619be09f3SLandon J. Fuller 
113719be09f3SLandon J. Fuller 			/* Now that we calculated the name offset, exclude all
113819be09f3SLandon J. Fuller 			 * trailing '/' characters from the path length */
113919be09f3SLandon J. Fuller 			while (path_len > 0 && path[path_len-1] == '/')
114019be09f3SLandon J. Fuller 				path_len--;
114119be09f3SLandon J. Fuller 
114219be09f3SLandon J. Fuller 			/* Perform standard validation on the relative
114319be09f3SLandon J. Fuller 			 * variable name */
114419be09f3SLandon J. Fuller 			if (type != BHND_NVSTORE_NAME_INTERNAL &&
114519be09f3SLandon J. Fuller 			    !bhnd_nvram_validate_name(relative_name))
114619be09f3SLandon J. Fuller 			{
114719be09f3SLandon J. Fuller 				return (ENOENT);
114819be09f3SLandon J. Fuller 			}
114919be09f3SLandon J. Fuller 
115019be09f3SLandon J. Fuller 			/* Initialize result with pointers into the name
115119be09f3SLandon J. Fuller 			 * buffer */
115219be09f3SLandon J. Fuller 			info->type = BHND_NVSTORE_VAR;
115319be09f3SLandon J. Fuller 			info->path_type = BHND_NVSTORE_PATH_STRING;
115419be09f3SLandon J. Fuller 			info->name = relative_name;
115519be09f3SLandon J. Fuller 			info->path.str.value = path;
115619be09f3SLandon J. Fuller 			info->path.str.value_len = path_len;
115719be09f3SLandon J. Fuller 
115819be09f3SLandon J. Fuller 			return (0);
115919be09f3SLandon J. Fuller 		}
116019be09f3SLandon J. Fuller 	}
116119be09f3SLandon J. Fuller 
116219be09f3SLandon J. Fuller 	/* If all other parsing fails, the result is a simple variable with
116319be09f3SLandon J. Fuller 	 * an implicit path of "/" */
116419be09f3SLandon J. Fuller 	if (type != BHND_NVSTORE_NAME_INTERNAL &&
116519be09f3SLandon J. Fuller 	    !bhnd_nvram_validate_name(name))
116619be09f3SLandon J. Fuller 	{
116719be09f3SLandon J. Fuller 		/* Invalid relative name */
116819be09f3SLandon J. Fuller 		return (ENOENT);
116919be09f3SLandon J. Fuller 	}
117019be09f3SLandon J. Fuller 
117119be09f3SLandon J. Fuller 	info->type = BHND_NVSTORE_VAR;
117219be09f3SLandon J. Fuller 	info->path_type = BHND_NVSTORE_PATH_STRING;
117319be09f3SLandon J. Fuller 	info->name = name;
117419be09f3SLandon J. Fuller 	info->path.str.value = BHND_NVSTORE_ROOT_PATH;
117519be09f3SLandon J. Fuller 	info->path.str.value_len = BHND_NVSTORE_ROOT_PATH_LEN;
117619be09f3SLandon J. Fuller 
117719be09f3SLandon J. Fuller 	return (0);
117819be09f3SLandon J. Fuller }
1179