xref: /openbsd-src/usr.sbin/ldomctl/mdesc.c (revision d73a4c4fb3962df1e72dd6910861075eabc6a1c3)
1*d73a4c4fSkn /*	$OpenBSD: mdesc.c,v 1.13 2019/11/28 18:40:42 kn Exp $	*/
2b01cf3d3Skettenis 
3b01cf3d3Skettenis /*
4b01cf3d3Skettenis  * Copyright (c) 2012 Mark Kettenis
5b01cf3d3Skettenis  *
6b01cf3d3Skettenis  * Permission to use, copy, modify, and distribute this software for any
7b01cf3d3Skettenis  * purpose with or without fee is hereby granted, provided that the above
8b01cf3d3Skettenis  * copyright notice and this permission notice appear in all copies.
9b01cf3d3Skettenis  *
10b01cf3d3Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11b01cf3d3Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12b01cf3d3Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13b01cf3d3Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14b01cf3d3Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15b01cf3d3Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16b01cf3d3Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17b01cf3d3Skettenis  */
18b01cf3d3Skettenis 
19b01cf3d3Skettenis #include <sys/types.h>
20b01cf3d3Skettenis #include <sys/queue.h>
21b01cf3d3Skettenis #include <err.h>
22b01cf3d3Skettenis #include <stdbool.h>
23b01cf3d3Skettenis #include <stdio.h>
24b01cf3d3Skettenis #include <stdlib.h>
25b01cf3d3Skettenis #include <string.h>
26b01cf3d3Skettenis 
27b01cf3d3Skettenis #include "mdesc.h"
28*d73a4c4fSkn #include "ldom_util.h"
29b01cf3d3Skettenis 
30b01cf3d3Skettenis struct md_name *
md_find_name(struct md * md,const char * str)31b01cf3d3Skettenis md_find_name(struct md *md, const char *str)
32b01cf3d3Skettenis {
33b01cf3d3Skettenis 	struct md_name *name;
34b01cf3d3Skettenis 
35b01cf3d3Skettenis 	TAILQ_FOREACH(name, &md->name_list, link)
36b01cf3d3Skettenis 		if (strcmp(name->str, str) == 0)
37b01cf3d3Skettenis 			return name;
38b01cf3d3Skettenis 	return NULL;
39b01cf3d3Skettenis }
40b01cf3d3Skettenis 
41b01cf3d3Skettenis struct md_name *
md_add_name(struct md * md,const char * str)42b01cf3d3Skettenis md_add_name(struct md *md, const char *str)
43b01cf3d3Skettenis {
44b01cf3d3Skettenis 	struct md_name *name;
45b01cf3d3Skettenis 
46b01cf3d3Skettenis 	name = md_find_name(md, str);
47b01cf3d3Skettenis 	if (name == NULL) {
48b01cf3d3Skettenis 		name = xmalloc(sizeof(*name));
49b01cf3d3Skettenis 		name->str = xstrdup(str);
50b01cf3d3Skettenis 		TAILQ_INSERT_TAIL(&md->name_list, name, link);
51b01cf3d3Skettenis 		name->refcnt = 0;
52b01cf3d3Skettenis 	}
53b01cf3d3Skettenis 	name->refcnt++;
54b01cf3d3Skettenis 	return name;
55b01cf3d3Skettenis }
56b01cf3d3Skettenis 
57b01cf3d3Skettenis void
md_free_name(struct md * md,struct md_name * name)58b01cf3d3Skettenis md_free_name(struct md *md, struct md_name *name)
59b01cf3d3Skettenis {
60b01cf3d3Skettenis 	if (name->refcnt > 1) {
61b01cf3d3Skettenis 		name->refcnt--;
62b01cf3d3Skettenis 		return;
63b01cf3d3Skettenis 	}
64b01cf3d3Skettenis 
65b01cf3d3Skettenis 	TAILQ_REMOVE(&md->name_list, name, link);
66b01cf3d3Skettenis 	free(name);
67b01cf3d3Skettenis }
68b01cf3d3Skettenis 
69b01cf3d3Skettenis struct md_data *
md_find_data(struct md * md,const uint8_t * b,size_t len)70b01cf3d3Skettenis md_find_data(struct md *md, const uint8_t *b, size_t len)
71b01cf3d3Skettenis {
72b01cf3d3Skettenis 	struct md_data *data;
73b01cf3d3Skettenis 
74b01cf3d3Skettenis 	TAILQ_FOREACH(data, &md->data_list, link)
75b01cf3d3Skettenis 		if (data->len == len &&
76b01cf3d3Skettenis 		    memcmp(data->data, b, len) == 0)
77b01cf3d3Skettenis 			return data;
78b01cf3d3Skettenis 
79b01cf3d3Skettenis 	return NULL;
80b01cf3d3Skettenis }
81b01cf3d3Skettenis 
82b01cf3d3Skettenis struct md_data *
md_add_data(struct md * md,const uint8_t * b,size_t len)83b01cf3d3Skettenis md_add_data(struct md *md, const uint8_t *b, size_t len)
84b01cf3d3Skettenis {
85b01cf3d3Skettenis 	struct md_data *data;
86b01cf3d3Skettenis 
87b01cf3d3Skettenis 	data = md_find_data(md, b, len);
88b01cf3d3Skettenis 	if (data == NULL) {
89b01cf3d3Skettenis 		data = xmalloc(sizeof(*data));
90b01cf3d3Skettenis 		data->data = xmalloc(len);
91b01cf3d3Skettenis 		memcpy(data->data, b, len);
92b01cf3d3Skettenis 		data->len = len;
93b01cf3d3Skettenis 		TAILQ_INSERT_TAIL(&md->data_list, data, link);
94b01cf3d3Skettenis 		data->refcnt = 0;
95b01cf3d3Skettenis 	}
96b01cf3d3Skettenis 	data->refcnt++;
97b01cf3d3Skettenis 	return data;
98b01cf3d3Skettenis }
99b01cf3d3Skettenis 
100b01cf3d3Skettenis void
md_free_data(struct md * md,struct md_data * data)101b01cf3d3Skettenis md_free_data(struct md *md, struct md_data *data)
102b01cf3d3Skettenis {
103b01cf3d3Skettenis 	if (data->refcnt > 1) {
104b01cf3d3Skettenis 		data->refcnt--;
105b01cf3d3Skettenis 		return;
106b01cf3d3Skettenis 	}
107b01cf3d3Skettenis 
108b01cf3d3Skettenis 	TAILQ_REMOVE(&md->data_list, data, link);
109b01cf3d3Skettenis 	free(data);
110b01cf3d3Skettenis }
111b01cf3d3Skettenis 
112b01cf3d3Skettenis struct md_node *
md_find_node(struct md * md,const char * name)113b01cf3d3Skettenis md_find_node(struct md *md, const char *name)
114b01cf3d3Skettenis {
115b01cf3d3Skettenis 	struct md_node *node;
116b01cf3d3Skettenis 
117b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
118b01cf3d3Skettenis 		if (strcmp(node->name->str, name) == 0)
119b01cf3d3Skettenis 			return node;
120b01cf3d3Skettenis 	}
121b01cf3d3Skettenis 
122b01cf3d3Skettenis 	return NULL;
123b01cf3d3Skettenis }
124b01cf3d3Skettenis 
125b01cf3d3Skettenis struct md_node *
md_find_subnode(struct md * md,struct md_node * node,const char * name)126d27a0d69Skettenis md_find_subnode(struct md *md, struct md_node *node, const char *name)
127d27a0d69Skettenis {
128d27a0d69Skettenis 	struct md_prop *prop;
129d27a0d69Skettenis 
130d27a0d69Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
131d27a0d69Skettenis 		if (prop->tag == MD_PROP_ARC &&
132d27a0d69Skettenis 		    strcmp(prop->name->str, "fwd") == 0 &&
133d27a0d69Skettenis 		    strcmp(prop->d.arc.node->name->str, name) == 0)
134d27a0d69Skettenis 			return prop->d.arc.node;
135d27a0d69Skettenis 	}
136d27a0d69Skettenis 
137d27a0d69Skettenis 	return NULL;
138d27a0d69Skettenis }
139d27a0d69Skettenis 
140d27a0d69Skettenis struct md_node *
md_add_node(struct md * md,const char * name)141b01cf3d3Skettenis md_add_node(struct md *md, const char *name)
142b01cf3d3Skettenis {
143b01cf3d3Skettenis 	struct md_node *node;
144b01cf3d3Skettenis 
145b01cf3d3Skettenis 	node = xmalloc(sizeof(*node));
146b01cf3d3Skettenis 	node->name = md_add_name(md, name);
147b01cf3d3Skettenis 	TAILQ_INIT(&node->prop_list);
148b01cf3d3Skettenis 	TAILQ_INSERT_TAIL(&md->node_list, node, link);
149b01cf3d3Skettenis 
150b01cf3d3Skettenis 	return node;
151b01cf3d3Skettenis }
152b01cf3d3Skettenis 
153b01cf3d3Skettenis void
md_link_node(struct md * md,struct md_node * node1,struct md_node * node2)154b01cf3d3Skettenis md_link_node(struct md *md, struct md_node *node1, struct md_node *node2)
155b01cf3d3Skettenis {
156b01cf3d3Skettenis 	md_add_prop_arc(md, node1, "fwd", node2);
157b01cf3d3Skettenis 	md_add_prop_arc(md, node2, "back", node1);
158b01cf3d3Skettenis }
159b01cf3d3Skettenis 
160b01cf3d3Skettenis struct md_prop *
md_find_prop(struct md * md,struct md_node * node,const char * name)161b01cf3d3Skettenis md_find_prop(struct md *md, struct md_node *node, const char *name)
162b01cf3d3Skettenis {
163b01cf3d3Skettenis 	struct md_prop *prop;
164b01cf3d3Skettenis 
165b01cf3d3Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
166b01cf3d3Skettenis 		if (strcmp(prop->name->str, name) == 0)
167b01cf3d3Skettenis 			return prop;
168b01cf3d3Skettenis 	}
169b01cf3d3Skettenis 
170b01cf3d3Skettenis 	return NULL;
171b01cf3d3Skettenis }
172b01cf3d3Skettenis 
173b01cf3d3Skettenis struct md_prop *
md_add_prop(struct md * md,struct md_node * node,const char * name)174b01cf3d3Skettenis md_add_prop(struct md *md, struct md_node *node, const char *name)
175b01cf3d3Skettenis {
176b01cf3d3Skettenis 	struct md_prop *prop;
177b01cf3d3Skettenis 
178b01cf3d3Skettenis 	prop = xmalloc(sizeof(*prop));
179b01cf3d3Skettenis 	prop->name = md_add_name(md, name);
180b01cf3d3Skettenis 	TAILQ_INSERT_TAIL(&node->prop_list, prop, link);
181b01cf3d3Skettenis 
182b01cf3d3Skettenis 	return prop;
183b01cf3d3Skettenis }
184b01cf3d3Skettenis 
185b01cf3d3Skettenis struct md_prop *
md_add_prop_val(struct md * md,struct md_node * node,const char * name,uint64_t val)186b01cf3d3Skettenis md_add_prop_val(struct md *md, struct md_node *node, const char *name,
187b01cf3d3Skettenis      uint64_t val)
188b01cf3d3Skettenis {
189b01cf3d3Skettenis 	struct md_prop *prop;
190b01cf3d3Skettenis 
191b01cf3d3Skettenis 	prop = md_add_prop(md, node, name);
192b01cf3d3Skettenis 	prop->tag = MD_PROP_VAL;
193b01cf3d3Skettenis 	prop->d.val = val;
194b01cf3d3Skettenis 
195b01cf3d3Skettenis 	return prop;
196b01cf3d3Skettenis }
197b01cf3d3Skettenis 
198b01cf3d3Skettenis struct md_prop *
md_add_prop_str(struct md * md,struct md_node * node,const char * name,const char * str)199b01cf3d3Skettenis md_add_prop_str(struct md *md, struct md_node *node, const char *name,
200b01cf3d3Skettenis      const char *str)
201b01cf3d3Skettenis {
202b01cf3d3Skettenis 	struct md_prop *prop;
203b01cf3d3Skettenis 
204b01cf3d3Skettenis 	prop = md_add_prop(md, node, name);
205b01cf3d3Skettenis 	prop->tag = MD_PROP_STR;
206b01cf3d3Skettenis 	prop->d.data = md_add_data(md, str, strlen(str) + 1);
207b01cf3d3Skettenis 
208b01cf3d3Skettenis 	return prop;
209b01cf3d3Skettenis }
210b01cf3d3Skettenis 
211b01cf3d3Skettenis struct md_prop *
md_add_prop_data(struct md * md,struct md_node * node,const char * name,const uint8_t * data,size_t len)212b01cf3d3Skettenis md_add_prop_data(struct md *md, struct md_node *node, const char *name,
213b01cf3d3Skettenis      const uint8_t *data, size_t len)
214b01cf3d3Skettenis {
215b01cf3d3Skettenis 	struct md_prop *prop;
216b01cf3d3Skettenis 
217b01cf3d3Skettenis 	prop = md_add_prop(md, node, name);
218b01cf3d3Skettenis 	prop->tag = MD_PROP_DATA;
219b01cf3d3Skettenis 	prop->d.data = md_add_data(md, data, len);
220b01cf3d3Skettenis 
221b01cf3d3Skettenis 	return prop;
222b01cf3d3Skettenis }
223b01cf3d3Skettenis 
224b01cf3d3Skettenis struct md_prop *
md_add_prop_arc(struct md * md,struct md_node * node,const char * name,struct md_node * target_node)225b01cf3d3Skettenis md_add_prop_arc(struct md *md, struct md_node *node, const char *name,
226b01cf3d3Skettenis     struct md_node *target_node)
227b01cf3d3Skettenis {
228b01cf3d3Skettenis 	struct md_prop *prop;
229b01cf3d3Skettenis 
230b01cf3d3Skettenis 	prop = md_add_prop(md, node, name);
231b01cf3d3Skettenis 	prop->tag = MD_PROP_ARC;
232b01cf3d3Skettenis 	prop->d.arc.node = target_node;
233b01cf3d3Skettenis 
234b01cf3d3Skettenis 	return prop;
235b01cf3d3Skettenis }
236b01cf3d3Skettenis 
237b01cf3d3Skettenis void
md_delete_prop(struct md * md,struct md_node * node,struct md_prop * prop)238b01cf3d3Skettenis md_delete_prop(struct md *md, struct md_node *node, struct md_prop *prop)
239b01cf3d3Skettenis {
240b01cf3d3Skettenis 	TAILQ_REMOVE(&node->prop_list, prop, link);
241b01cf3d3Skettenis 	if (prop->tag == MD_PROP_STR || prop->tag == MD_PROP_DATA)
242b01cf3d3Skettenis 		md_free_data(md, prop->d.data);
243b01cf3d3Skettenis 	md_free_name(md, prop->name);
244b01cf3d3Skettenis 	free(prop);
245b01cf3d3Skettenis }
246b01cf3d3Skettenis 
247b01cf3d3Skettenis bool
md_get_prop_val(struct md * md,struct md_node * node,const char * name,uint64_t * val)248b01cf3d3Skettenis md_get_prop_val(struct md *md, struct md_node *node, const char *name,
249b01cf3d3Skettenis     uint64_t *val)
250b01cf3d3Skettenis {
251b01cf3d3Skettenis 	struct md_prop *prop;
252b01cf3d3Skettenis 
253b01cf3d3Skettenis 	prop = md_find_prop(md, node, name);
254e099dd74Skettenis 	if (prop == NULL || prop->tag != MD_PROP_VAL)
255b01cf3d3Skettenis 		return false;
256b01cf3d3Skettenis 
257b01cf3d3Skettenis 	*val = prop->d.val;
258b01cf3d3Skettenis 	return true;
259b01cf3d3Skettenis }
260b01cf3d3Skettenis 
261b01cf3d3Skettenis bool
md_set_prop_val(struct md * md,struct md_node * node,const char * name,uint64_t val)2628d715939Skettenis md_set_prop_val(struct md *md, struct md_node *node, const char *name,
2638d715939Skettenis     uint64_t val)
2648d715939Skettenis {
2658d715939Skettenis 	struct md_prop *prop;
2668d715939Skettenis 
2678d715939Skettenis 	prop = md_find_prop(md, node, name);
2688d715939Skettenis 	if (prop == NULL || prop->tag != MD_PROP_VAL)
2698d715939Skettenis 		return false;
2708d715939Skettenis 
2718d715939Skettenis 	prop->d.val = val;
2728d715939Skettenis 	return true;
2738d715939Skettenis }
2748d715939Skettenis 
2758d715939Skettenis bool
md_get_prop_str(struct md * md,struct md_node * node,const char * name,const char ** str)276b01cf3d3Skettenis md_get_prop_str(struct md *md, struct md_node *node, const char *name,
277b01cf3d3Skettenis     const char **str)
278b01cf3d3Skettenis {
279b01cf3d3Skettenis 	struct md_prop *prop;
280b01cf3d3Skettenis 
281b01cf3d3Skettenis 	prop = md_find_prop(md, node, name);
282b01cf3d3Skettenis 	if (prop == NULL || prop->tag != MD_PROP_STR)
283b01cf3d3Skettenis 		return false;
284b01cf3d3Skettenis 
285b01cf3d3Skettenis 	*str = prop->d.data->data;
286b01cf3d3Skettenis 	return true;
287b01cf3d3Skettenis }
288b01cf3d3Skettenis 
289b01cf3d3Skettenis bool
md_get_prop_data(struct md * md,struct md_node * node,const char * name,const void ** data,size_t * len)290b01cf3d3Skettenis md_get_prop_data(struct md *md, struct md_node *node, const char *name,
291b01cf3d3Skettenis     const void **data, size_t *len)
292b01cf3d3Skettenis {
293b01cf3d3Skettenis 	struct md_prop *prop;
294b01cf3d3Skettenis 
295b01cf3d3Skettenis 	prop = md_find_prop(md, node, name);
296b01cf3d3Skettenis 	if (prop == NULL || prop->tag != MD_PROP_DATA)
297b01cf3d3Skettenis 		return false;
298b01cf3d3Skettenis 
299b01cf3d3Skettenis 	*data = prop->d.data->data;
300b01cf3d3Skettenis 	*len = prop->d.data->len;
301b01cf3d3Skettenis 	return true;
302b01cf3d3Skettenis }
303b01cf3d3Skettenis 
304aace55b7Skettenis bool
md_set_prop_data(struct md * md,struct md_node * node,const char * name,const uint8_t * data,size_t len)305aace55b7Skettenis md_set_prop_data(struct md *md, struct md_node *node, const char *name,
306aace55b7Skettenis 		 const uint8_t *data, size_t len)
307aace55b7Skettenis {
308aace55b7Skettenis 	struct md_prop *prop;
309aace55b7Skettenis 
310aace55b7Skettenis 	prop = md_find_prop(md, node, name);
311aace55b7Skettenis 	if (prop == NULL || prop->tag != MD_PROP_DATA)
312aace55b7Skettenis 		return false;
313aace55b7Skettenis 
314aace55b7Skettenis 	md_free_data(md, prop->d.data);
315aace55b7Skettenis 	prop->d.data = md_add_data(md, data, len);
316aace55b7Skettenis 	return true;
317aace55b7Skettenis }
318aace55b7Skettenis 
319b01cf3d3Skettenis void
md_delete_node(struct md * md,struct md_node * node)320b01cf3d3Skettenis md_delete_node(struct md *md, struct md_node *node)
321b01cf3d3Skettenis {
322b01cf3d3Skettenis 	struct md_node *node2;
323b01cf3d3Skettenis 	struct md_prop *prop, *prop2;
324b01cf3d3Skettenis 
325b01cf3d3Skettenis 	TAILQ_FOREACH(node2, &md->node_list, link) {
326b01cf3d3Skettenis 		TAILQ_FOREACH_SAFE(prop, &node2->prop_list, link, prop2) {
327b01cf3d3Skettenis 			if (prop->tag == MD_PROP_ARC &&
328b01cf3d3Skettenis 			    prop->d.arc.node == node)
329b01cf3d3Skettenis 				md_delete_prop(md, node2, prop);
330b01cf3d3Skettenis 		}
331b01cf3d3Skettenis 	}
332b01cf3d3Skettenis 
333b01cf3d3Skettenis 	TAILQ_REMOVE(&md->node_list, node, link);
334b01cf3d3Skettenis 	md_free_name(md, node->name);
335b01cf3d3Skettenis 	free(node);
336b01cf3d3Skettenis }
337b01cf3d3Skettenis 
338b01cf3d3Skettenis void
md_find_delete_node(struct md * md,const char * name)339b01cf3d3Skettenis md_find_delete_node(struct md *md, const char *name)
340b01cf3d3Skettenis {
341b01cf3d3Skettenis 	struct md_node *node;
342b01cf3d3Skettenis 
343b01cf3d3Skettenis 	node = md_find_node(md, name);
344b01cf3d3Skettenis 	if (node)
345b01cf3d3Skettenis 		md_delete_node(md, node);
346b01cf3d3Skettenis }
347b01cf3d3Skettenis 
348b01cf3d3Skettenis struct md *
md_alloc(void)349b01cf3d3Skettenis md_alloc(void)
350b01cf3d3Skettenis {
351b01cf3d3Skettenis 	struct md *md;
352b01cf3d3Skettenis 
353b01cf3d3Skettenis 	md = xmalloc(sizeof(*md));
354b01cf3d3Skettenis 	TAILQ_INIT(&md->node_list);
355b01cf3d3Skettenis 	TAILQ_INIT(&md->name_list);
356b01cf3d3Skettenis 	TAILQ_INIT(&md->data_list);
357b01cf3d3Skettenis 
358b01cf3d3Skettenis 	return md;
359b01cf3d3Skettenis }
360b01cf3d3Skettenis 
361b01cf3d3Skettenis struct md_node *
md_find_index(struct md * md,uint64_t index)362b01cf3d3Skettenis md_find_index(struct md *md, uint64_t index)
363b01cf3d3Skettenis {
364b01cf3d3Skettenis 	struct md_node *node;
365b01cf3d3Skettenis 
366b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
367b01cf3d3Skettenis 		if (node->index == index)
368b01cf3d3Skettenis 			return node;
369b01cf3d3Skettenis 	}
370b01cf3d3Skettenis 
371b01cf3d3Skettenis 	return NULL;
372b01cf3d3Skettenis }
373b01cf3d3Skettenis 
374b01cf3d3Skettenis void
md_fixup_arcs(struct md * md)375b01cf3d3Skettenis md_fixup_arcs(struct md *md)
376b01cf3d3Skettenis {
377b01cf3d3Skettenis 	struct md_node *node;
378b01cf3d3Skettenis 	struct md_prop *prop;
379b01cf3d3Skettenis 
380b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
381b01cf3d3Skettenis 		TAILQ_FOREACH(prop, &node->prop_list, link) {
382b01cf3d3Skettenis 			if (prop->tag == MD_PROP_ARC)
383b01cf3d3Skettenis 				prop->d.arc.node =
384b01cf3d3Skettenis 				    md_find_index(md, prop->d.arc.index);
385b01cf3d3Skettenis 		}
386b01cf3d3Skettenis 	}
387b01cf3d3Skettenis }
388b01cf3d3Skettenis 
389b01cf3d3Skettenis void
md_walk_graph(struct md * md,struct md_node * root)390b01cf3d3Skettenis md_walk_graph(struct md *md, struct md_node *root)
391b01cf3d3Skettenis {
392b01cf3d3Skettenis 	struct md_prop *prop;
393b01cf3d3Skettenis 
394b01cf3d3Skettenis 	root->index = 1;
395b01cf3d3Skettenis 	TAILQ_FOREACH(prop, &root->prop_list, link) {
396b01cf3d3Skettenis 		if (prop->tag == MD_PROP_ARC &&
397b01cf3d3Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
398b01cf3d3Skettenis 			md_walk_graph(md, prop->d.arc.node);
399b01cf3d3Skettenis 	}
400b01cf3d3Skettenis }
401b01cf3d3Skettenis 
402b01cf3d3Skettenis void
md_collect_garbage(struct md * md)403b01cf3d3Skettenis md_collect_garbage(struct md *md)
404b01cf3d3Skettenis {
405b01cf3d3Skettenis 	struct md_node *node, *node2;
406b01cf3d3Skettenis 
407b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link)
408b01cf3d3Skettenis 		node->index = 0;
409b01cf3d3Skettenis 
410b01cf3d3Skettenis 	md_walk_graph(md, md_find_node(md, "root"));
411b01cf3d3Skettenis 
412b01cf3d3Skettenis 	TAILQ_FOREACH_SAFE(node, &md->node_list, link, node2) {
413b01cf3d3Skettenis 		if (node->index == 0)
414b01cf3d3Skettenis 			md_delete_node(md, node);
415b01cf3d3Skettenis 	}
416b01cf3d3Skettenis }
417b01cf3d3Skettenis 
418b01cf3d3Skettenis struct md *
md_ingest(void * buf,size_t size)419b01cf3d3Skettenis md_ingest(void *buf, size_t size)
420b01cf3d3Skettenis {
421b01cf3d3Skettenis 	struct md_header *mdh = buf;
422b01cf3d3Skettenis 	size_t node_blk_size, name_blk_size, data_blk_size;
423b01cf3d3Skettenis 	size_t total_size;
424b01cf3d3Skettenis 	struct md_element *mde;
425b01cf3d3Skettenis 	struct md_node *node = NULL;
426b01cf3d3Skettenis 	struct md_prop *prop;
427b01cf3d3Skettenis 	struct md *md;
428b01cf3d3Skettenis 	const char *str;
429b01cf3d3Skettenis 	const uint8_t *data;
430b01cf3d3Skettenis 	uint8_t *node_blk;
431b01cf3d3Skettenis 	uint8_t *name_blk;
432b01cf3d3Skettenis 	uint8_t *data_blk;
433b01cf3d3Skettenis 	uint64_t index;
434b01cf3d3Skettenis 
435b01cf3d3Skettenis 	if (size < sizeof(struct md_header))
436b01cf3d3Skettenis 		errx(1, "too small");
437b01cf3d3Skettenis 
438b01cf3d3Skettenis 	if (betoh32(mdh->transport_version) != MD_TRANSPORT_VERSION)
439b01cf3d3Skettenis 		errx(1, "invalid transport version");
440b01cf3d3Skettenis 
441b01cf3d3Skettenis 	node_blk_size = betoh32(mdh->node_blk_sz);
442b01cf3d3Skettenis 	name_blk_size = betoh32(mdh->name_blk_sz);
443b01cf3d3Skettenis 	data_blk_size = betoh32(mdh->data_blk_sz);
444b01cf3d3Skettenis 	total_size = node_blk_size + name_blk_size + data_blk_size;
445b01cf3d3Skettenis 
446b01cf3d3Skettenis 	if (size < total_size)
447b01cf3d3Skettenis 		errx(1, "too small");
448b01cf3d3Skettenis 
449b01cf3d3Skettenis 	md = md_alloc();
450b01cf3d3Skettenis 
451b01cf3d3Skettenis 	mde = (void *)&mdh[1];
452b01cf3d3Skettenis 	node_blk = (void *)mde;
453b01cf3d3Skettenis 	name_blk = node_blk + node_blk_size;
454b01cf3d3Skettenis 	data_blk = name_blk + name_blk_size;
455b01cf3d3Skettenis 
456b01cf3d3Skettenis 	for (index = 0; index < node_blk_size / sizeof(*mde); index++, mde++) {
457b01cf3d3Skettenis 		switch(mde->tag) {
458b01cf3d3Skettenis 		case MD_NODE:
459b01cf3d3Skettenis 			str = name_blk + betoh32(mde->name_offset);
460b01cf3d3Skettenis 			node = md_add_node(md, str);
461b01cf3d3Skettenis 			node->index = index;
462b01cf3d3Skettenis 			break;
463b01cf3d3Skettenis 		case MD_PROP_VAL:
464b01cf3d3Skettenis 			if (node == NULL)
465b01cf3d3Skettenis 				errx(1, "Corrupt MD");
466b01cf3d3Skettenis 			str = name_blk + betoh32(mde->name_offset);
467b01cf3d3Skettenis 			md_add_prop_val(md, node, str, betoh64(mde->d.val));
468b01cf3d3Skettenis 			break;
469b01cf3d3Skettenis 		case MD_PROP_STR:
470b01cf3d3Skettenis 			if (node == NULL)
471b01cf3d3Skettenis 				errx(1, "Corrupt MD");
472b01cf3d3Skettenis 			str = name_blk + betoh32(mde->name_offset);
473b01cf3d3Skettenis 			data = data_blk + betoh32(mde->d.y.data_offset);
474b01cf3d3Skettenis 			md_add_prop_str(md, node, str, data);
475b01cf3d3Skettenis 			break;
476b01cf3d3Skettenis 		case MD_PROP_DATA:
477b01cf3d3Skettenis 			if (node == NULL)
478b01cf3d3Skettenis 				errx(1, "Corrupt MD");
479b01cf3d3Skettenis 			str = name_blk + betoh32(mde->name_offset);
480b01cf3d3Skettenis 			data = data_blk + betoh32(mde->d.y.data_offset);
481b01cf3d3Skettenis 			md_add_prop_data(md, node, str, data,
482b01cf3d3Skettenis 			    betoh32(mde->d.y.data_len));
483b01cf3d3Skettenis 			break;
484b01cf3d3Skettenis 		case MD_PROP_ARC:
485b01cf3d3Skettenis 			if (node == NULL)
486b01cf3d3Skettenis 				errx(1, "Corrupt MD");
487b01cf3d3Skettenis 			str = name_blk + betoh32(mde->name_offset);
488b01cf3d3Skettenis 			prop = md_add_prop(md, node, str);
489b01cf3d3Skettenis 			prop->tag = MD_PROP_ARC;
490b01cf3d3Skettenis 			prop->d.arc.index = betoh64(mde->d.val);
491b01cf3d3Skettenis 			prop->d.arc.node = NULL;
492b01cf3d3Skettenis 			break;
493b01cf3d3Skettenis 		case MD_NODE_END:
494b01cf3d3Skettenis 			node = NULL;
495b01cf3d3Skettenis 			break;
496b01cf3d3Skettenis 		}
497b01cf3d3Skettenis 	}
498b01cf3d3Skettenis 
499b01cf3d3Skettenis 	md_fixup_arcs(md);
500b01cf3d3Skettenis 
501b01cf3d3Skettenis 	return md;
502b01cf3d3Skettenis }
503b01cf3d3Skettenis 
504b01cf3d3Skettenis size_t
md_exhume(struct md * md,void ** buf)505b01cf3d3Skettenis md_exhume(struct md *md, void **buf)
506b01cf3d3Skettenis {
507b01cf3d3Skettenis 	struct md_node *node;
508b01cf3d3Skettenis 	struct md_name *name;
509b01cf3d3Skettenis 	struct md_data *data;
510b01cf3d3Skettenis 	struct md_prop *prop;
511b01cf3d3Skettenis 	size_t node_blk_size, name_blk_size, data_blk_size;
512b01cf3d3Skettenis 	size_t total_size;
513b01cf3d3Skettenis 	struct md_element *mde;
514b01cf3d3Skettenis 	struct md_header *mdh;
515b01cf3d3Skettenis 	uint32_t offset;
516b01cf3d3Skettenis 	uint64_t index;
517b01cf3d3Skettenis 	uint8_t *node_blk;
518b01cf3d3Skettenis 	uint8_t *name_blk;
519b01cf3d3Skettenis 	uint8_t *data_blk;
520b01cf3d3Skettenis 	size_t len;
521b01cf3d3Skettenis 
522b01cf3d3Skettenis 	offset = 0;
523b01cf3d3Skettenis 	TAILQ_FOREACH(name, &md->name_list, link) {
524b01cf3d3Skettenis 		name->offset = offset;
525b01cf3d3Skettenis 		offset += (strlen(name->str) + 1);
526b01cf3d3Skettenis 	}
527b01cf3d3Skettenis 	name_blk_size = roundup(offset, MD_ALIGNMENT_SIZE);
528b01cf3d3Skettenis 
529b01cf3d3Skettenis 	offset = 0;
530b01cf3d3Skettenis 	TAILQ_FOREACH(data, &md->data_list, link) {
531b01cf3d3Skettenis 		data->offset = offset;
532b01cf3d3Skettenis 		offset += data->len;
533b01cf3d3Skettenis 		offset = roundup(offset, MD_ALIGNMENT_SIZE);
534b01cf3d3Skettenis 	}
535b01cf3d3Skettenis 	data_blk_size = roundup(offset, MD_ALIGNMENT_SIZE);
536b01cf3d3Skettenis 
537b01cf3d3Skettenis 	index = 0;
538b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
539b01cf3d3Skettenis 		node->index = index;
540b01cf3d3Skettenis 		TAILQ_FOREACH(prop, &node->prop_list, link)
541b01cf3d3Skettenis 			index++;
542b01cf3d3Skettenis 		index += 2;
543b01cf3d3Skettenis 	}
544b01cf3d3Skettenis 	node_blk_size = (index + 1) * sizeof(struct md_element);
545b01cf3d3Skettenis 
546b01cf3d3Skettenis 	total_size = 16 + node_blk_size + name_blk_size + data_blk_size;
547b01cf3d3Skettenis 	mdh = xmalloc(total_size);
548b01cf3d3Skettenis 
549b01cf3d3Skettenis 	mdh->transport_version = htobe32(MD_TRANSPORT_VERSION);
550b01cf3d3Skettenis 	mdh->node_blk_sz = htobe32(node_blk_size);
551b01cf3d3Skettenis 	mdh->name_blk_sz = htobe32(name_blk_size);
552b01cf3d3Skettenis 	mdh->data_blk_sz = htobe32(data_blk_size);
553b01cf3d3Skettenis 
554b01cf3d3Skettenis 	mde = (void *)&mdh[1];
555b01cf3d3Skettenis 	node_blk = (void *)mde;
556b01cf3d3Skettenis 	name_blk = node_blk + node_blk_size;
557b01cf3d3Skettenis 	data_blk = name_blk + name_blk_size;
558b01cf3d3Skettenis 
559b01cf3d3Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
560b01cf3d3Skettenis 		memset(mde, 0, sizeof(*mde));
561b01cf3d3Skettenis 		mde->tag = MD_NODE;
562b01cf3d3Skettenis 		mde->name_len = strlen(node->name->str);
563b01cf3d3Skettenis 		mde->name_offset = htobe32(node->name->offset);
564b01cf3d3Skettenis 		if (TAILQ_NEXT(node, link))
565b01cf3d3Skettenis 			mde->d.val = htobe64(TAILQ_NEXT(node, link)->index);
566b01cf3d3Skettenis 		else
567b01cf3d3Skettenis 			mde->d.val = htobe64(index);
568b01cf3d3Skettenis 		mde++;
569b01cf3d3Skettenis 		TAILQ_FOREACH(prop, &node->prop_list, link) {
570b01cf3d3Skettenis 			memset(mde, 0, sizeof(*mde));
571b01cf3d3Skettenis 			mde->tag = prop->tag;
572b01cf3d3Skettenis 			mde->name_len = strlen(prop->name->str);
573b01cf3d3Skettenis 			mde->name_offset = htobe32(prop->name->offset);
574b01cf3d3Skettenis 			switch(prop->tag) {
575b01cf3d3Skettenis 			case MD_PROP_VAL:
576b01cf3d3Skettenis 				mde->d.val = htobe64(prop->d.val);
577b01cf3d3Skettenis 				break;
578b01cf3d3Skettenis 			case MD_PROP_STR:
579b01cf3d3Skettenis 			case MD_PROP_DATA:
580b01cf3d3Skettenis 				mde->d.y.data_len =
581b01cf3d3Skettenis 				    htobe32(prop->d.data->len);
582b01cf3d3Skettenis 				mde->d.y.data_offset =
583b01cf3d3Skettenis 				    htobe32(prop->d.data->offset);
584b01cf3d3Skettenis 				break;
585b01cf3d3Skettenis 			case MD_PROP_ARC:
586b01cf3d3Skettenis 				mde->d.val =
587b01cf3d3Skettenis 				    htobe64(prop->d.arc.node->index);
588b01cf3d3Skettenis 				break;
589b01cf3d3Skettenis 			}
590b01cf3d3Skettenis 			mde++;
591b01cf3d3Skettenis 		}
592b01cf3d3Skettenis 		memset(mde, 0, sizeof(*mde));
593b01cf3d3Skettenis 		mde->tag = MD_NODE_END;
594b01cf3d3Skettenis 		mde++;
595b01cf3d3Skettenis 	}
596b01cf3d3Skettenis 	memset(mde, 0, sizeof(*mde));
597b01cf3d3Skettenis 	mde->tag = MD_LIST_END;
598b01cf3d3Skettenis 
599b01cf3d3Skettenis 	TAILQ_FOREACH(name, &md->name_list, link) {
600b01cf3d3Skettenis 		len = strlen(name->str) + 1;
601b01cf3d3Skettenis 		memcpy(name_blk, name->str, len);
602b01cf3d3Skettenis 		name_blk += len;
603b01cf3d3Skettenis 	}
604b01cf3d3Skettenis 
605b01cf3d3Skettenis 	TAILQ_FOREACH(data, &md->data_list, link) {
606b01cf3d3Skettenis 		memcpy(data_blk, data->data, data->len);
607b01cf3d3Skettenis 		data_blk += roundup(data->len, MD_ALIGNMENT_SIZE);
608b01cf3d3Skettenis 	}
609b01cf3d3Skettenis 
610b01cf3d3Skettenis 	*buf = mdh;
611b01cf3d3Skettenis 	return total_size;
612b01cf3d3Skettenis }
613b01cf3d3Skettenis 
614b01cf3d3Skettenis struct md *
md_copy(struct md * md)615b01cf3d3Skettenis md_copy(struct md *md)
616b01cf3d3Skettenis {
617b01cf3d3Skettenis 	void *buf;
618b01cf3d3Skettenis 	size_t size;
619b01cf3d3Skettenis 
620b01cf3d3Skettenis 	size = md_exhume(md, &buf);
621b01cf3d3Skettenis 	md = md_ingest(buf, size);
622b01cf3d3Skettenis 	free(buf);
623b01cf3d3Skettenis 
624b01cf3d3Skettenis 	return md;
625b01cf3d3Skettenis }
626b01cf3d3Skettenis 
627b01cf3d3Skettenis struct md *
md_read(const char * path)628b01cf3d3Skettenis md_read(const char *path)
629b01cf3d3Skettenis {
630b01cf3d3Skettenis 	FILE *fp;
631b01cf3d3Skettenis 	size_t size;
632b01cf3d3Skettenis 	void *buf;
633b01cf3d3Skettenis 
634b01cf3d3Skettenis 	fp = fopen(path, "r");
635b01cf3d3Skettenis 	if (fp == NULL)
636b01cf3d3Skettenis 		return NULL;
637b01cf3d3Skettenis 
638f09e271fSjsg 	if (fseek(fp, 0, SEEK_END) == -1) {
639f09e271fSjsg 		fclose(fp);
640b01cf3d3Skettenis 		return NULL;
641f09e271fSjsg 	}
642b01cf3d3Skettenis 	size = ftell(fp);
643f09e271fSjsg 	if (size == -1) {
644f09e271fSjsg 		fclose(fp);
645b01cf3d3Skettenis 		return NULL;
646f09e271fSjsg 	}
647f09e271fSjsg 	if (fseek(fp, 0, SEEK_SET) == -1) {
648f09e271fSjsg 		fclose(fp);
649b01cf3d3Skettenis 		return NULL;
650f09e271fSjsg 	}
651b01cf3d3Skettenis 
652b01cf3d3Skettenis 	buf = xmalloc(size);
653f09e271fSjsg 	if (fread(buf, size, 1, fp) != 1) {
654f09e271fSjsg 		fclose(fp);
6550f498d25Sjsg 		free(buf);
656b01cf3d3Skettenis 		return NULL;
657f09e271fSjsg 	}
658b01cf3d3Skettenis 
659b01cf3d3Skettenis 	fclose(fp);
660b01cf3d3Skettenis 
661b01cf3d3Skettenis 	return md_ingest(buf, size);
662b01cf3d3Skettenis }
663b01cf3d3Skettenis 
664b01cf3d3Skettenis void
md_write(struct md * md,const char * path)665b01cf3d3Skettenis md_write(struct md *md, const char *path)
666b01cf3d3Skettenis {
667b01cf3d3Skettenis 	size_t size;
668b01cf3d3Skettenis 	void *buf;
669b01cf3d3Skettenis 	FILE *fp;
670b01cf3d3Skettenis 
671b01cf3d3Skettenis 	size = md_exhume(md, &buf);
672b01cf3d3Skettenis 
673b01cf3d3Skettenis 	fp = fopen(path, "w");
674b01cf3d3Skettenis 	if (fp == NULL)
675b01cf3d3Skettenis 		err(1, "fopen");
676b01cf3d3Skettenis 
677b01cf3d3Skettenis 	if (fwrite(buf, size, 1, fp) != 1)
678b01cf3d3Skettenis 		err(1, "fwrite");
679b01cf3d3Skettenis 
680b01cf3d3Skettenis 	fclose(fp);
681b01cf3d3Skettenis }
682c994384aSkettenis 
683c994384aSkettenis uint32_t
md_size(const char * path)684c994384aSkettenis md_size(const char *path)
685c994384aSkettenis {
686c994384aSkettenis 	uint32_t size;
687c994384aSkettenis 	FILE *fp;
688c994384aSkettenis 
689c994384aSkettenis 	fp = fopen(path, "r");
690c994384aSkettenis 	if (fp == NULL)
691c994384aSkettenis 		err(1, "fopen");
692c994384aSkettenis 
693c994384aSkettenis 	fseek(fp, 0, SEEK_END);
694c994384aSkettenis 	size = ftell(fp);
695c994384aSkettenis 	fclose(fp);
696c994384aSkettenis 
697c994384aSkettenis 	return size;
698c994384aSkettenis }
699