ia64/xen-unstable

view xen/arch/powerpc/of-devtree.c @ 13950:272291dacad4

[POWERPC][XEN] strlcpy() fallout.
- Implement strlcpy() for the dom0 firmware.
- Remove strncpy() from dom0 firmware.
- Correct buffer length in device tree copying.
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Hollis Blanchard <hollisb@us.ibm.com>
date Fri Feb 09 14:43:21 2007 -0600 (2007-02-09)
parents d2784d93e760
children c9720159b983
line source
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2005
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 */
21 /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
22 * This code is intended to be used but relocatable routines So PLEASE
23 * do not place any global data here including const integrals or
24 * literals.
25 * The local assert() is ok for string literal usage.. but thats it.
26 */
29 #include <xen/config.h>
30 #include <xen/init.h>
31 #include <xen/lib.h>
32 #include "of-devtree.h"
34 static int (*ofd_write)(const char *, size_t len) = NULL;
36 void ofd_init(int (*write)(const char *, size_t len))
37 {
38 ofd_write = write;
39 }
42 static void ofd_stop(void)
43 {
44 for ( ; ; ) ;
45 }
47 /* this is so it can be called from anywhere */
48 static void ofd_assprint(int line)
49 {
50 char a[13];
51 char num[20];
52 int i;
54 a[0] = '\n';
55 a[1] = '\n';
56 a[2] = 'O';
57 a[3] = 'F';
58 a[4] = 'D';
59 a[5] = ':';
60 a[6] = 'A';
61 a[7] = 'S';
62 a[8] = 'S';
63 a[9] = 'E';
64 a[10] = 'R';
65 a[11] = 'T';
66 a[12] = ':';
69 ofd_write(a, sizeof (a) - 1);
71 /* put the number in backwards */
72 i = 0;
73 while ( line > 0 ) {
74 num[i++] = '0' + (line % 10);
75 line /= 10;
76 }
77 /* print it */
78 /* number */
79 while (i-- > 0) {
80 ofd_write(&num[i], 1);
81 }
82 ofd_write("\n", 1);
84 ofd_stop();
85 }
87 #ifdef assert
88 #undef assert
89 #endif
91 #define assert(EX) \
92 do { \
93 if ( !(EX) ) { \
94 ofd_assprint(__LINE__); \
95 } \
96 } while (0)
98 /*
99 * We treat memory like an array of u64. For the sake of
100 * compactness we assume that a short is big enough as an index.
101 */
102 struct ofd_node {
103 ofdn_t on_ima;
104 ofdn_t on_parent;
105 ofdn_t on_child;
106 ofdn_t on_peer;
107 ofdn_t on_io;
108 ofdn_t on_next; /* for search lists */
109 ofdn_t on_prev;
110 ofdn_t on_prop;
111 u32 on_pathlen;
112 u32 on_last;
113 char on_path[0];
114 };
116 struct ofd_prop {
117 ofdn_t op_ima;
118 ofdn_t op_next;
119 u32 op_objsz;
120 u32 op_namesz;
121 /* must have 64bit alignment */
122 char op_data[0] __attribute__ ((aligned(8)));
123 };
125 struct ofd_io {
126 ofdn_t oi_ima;
127 ofdn_t oi_node;
128 u64 oi_open __attribute__ ((aligned(8)));
129 };
131 struct ofd_free {
132 ofdn_t of_cells;
133 ofdn_t of_next;
134 };
136 struct ofd_mem {
137 ofdn_t om_num;
138 ofdn_t om_next;
139 ofdn_t om_free; /* Future site of a free list */
140 ofdn_t _om_pad;
141 u64 om_mem[0] __attribute__((aligned(8)));
142 };
144 #define NODE_PAT 0x0f01
145 #define PROP_PAT 0x0f03
146 #define IO_PAT 0x0f05
149 size_t ofd_size(void *mem)
150 {
151 struct ofd_mem *m = (struct ofd_mem *)mem;
152 size_t sz;
154 sz = m->om_next * sizeof (u64) + sizeof(*m);
155 return sz;
156 }
158 size_t ofd_space(void *mem)
159 {
160 struct ofd_mem *m = (struct ofd_mem *)mem;
161 size_t sz;
163 sz = m->om_num * sizeof (u64);
164 return sz;
165 }
168 static int ofd_pathsplit_right(const char *s, int c, size_t max)
169 {
170 int i = 0;
172 if ( max == 0 ) {
173 --max;
174 }
176 while ( *s != '\0' && *s != c && max != 0 ) {
177 ++i;
178 ++s;
179 --max;
180 }
181 return i;
182 }
184 static int ofd_pathsplit_left(const char *p, int c, size_t len)
185 {
186 const char *s;
188 if ( len > 0 ) {
189 /* move s to the end */
190 s = p + len - 1;
192 /* len could include a null */
193 if ( *s == '\0' ) {
194 --s;
195 }
196 while ( s >= p ) {
197 if ( *s == c ) {
198 ++s;
199 break;
200 }
201 --s;
202 }
203 if ( s < p ) {
204 return 0;
205 }
206 return (s - p);
207 }
208 return 0;
209 }
211 void *ofd_create(void *mem, size_t sz)
212 {
213 struct ofd_mem *m = (struct ofd_mem *)mem;
214 struct ofd_node *n;
215 size_t sum;
216 ofdn_t cells;
218 if ( sz < (sizeof (*n) * 4) ) {
219 return NULL;
220 }
222 memset(mem, 0, sz);
224 m->om_num = (sz - sizeof(*m)) / sizeof (u64);
226 /* skip the first cell */
227 m->om_next = OFD_ROOT;
228 n = (struct ofd_node *)&m->om_mem[m->om_next];
229 n->on_ima = NODE_PAT;
230 n->on_pathlen = 2;
231 n->on_last = 1;
232 n->on_path[0] = '/';
233 n->on_path[1] = '\0';
235 sum = sizeof (*n) + 2; /* Don't forget the path */
236 cells = (sum + sizeof (m->om_mem[0]) - 1) / sizeof (m->om_mem[0]);
237 m->om_next += cells;
239 return m;
240 }
242 static struct ofd_node *ofd_node_get(struct ofd_mem *m, ofdn_t n)
243 {
244 if ( n < m->om_next ) {
245 struct ofd_node *r;
247 r = (struct ofd_node *)&m->om_mem[n];
248 if ( r->on_ima == NODE_PAT ) {
249 return r;
250 }
251 }
252 return NULL;
253 }
255 ofdn_t ofd_node_parent(void *mem, ofdn_t n)
256 {
257 struct ofd_mem *m = (struct ofd_mem *)mem;
258 struct ofd_node *r = ofd_node_get(m, n);
260 if ( r == NULL) return 0;
261 return r->on_parent;
262 }
264 ofdn_t ofd_node_peer(void *mem, ofdn_t n)
265 {
266 struct ofd_mem *m = (struct ofd_mem *)mem;
267 struct ofd_node *r;
269 if ( n == 0 ) {
270 return OFD_ROOT;
271 }
273 r = ofd_node_get(m, n);
274 if ( r == NULL) return 0;
275 return r->on_peer;
276 }
278 const char *ofd_node_path(void *mem, ofdn_t n)
279 {
280 struct ofd_mem *m = (struct ofd_mem *)mem;
281 struct ofd_node *r = ofd_node_get(m, n);
283 if ( r == NULL) return NULL;
284 return r->on_path;
285 }
287 static ofdn_t ofd_node_prop(void *mem, ofdn_t n)
288 {
289 struct ofd_mem *m = (struct ofd_mem *)mem;
290 struct ofd_node *r = ofd_node_get(m, n);
292 if ( r == NULL) return 0;
293 return r->on_prop;
294 }
296 ofdn_t ofd_node_child(void *mem, ofdn_t p)
297 {
298 struct ofd_mem *m = (struct ofd_mem *)mem;
299 struct ofd_node *r = ofd_node_get(m, p);
301 if ( r == NULL) return 0;
302 return r->on_child;
303 }
305 int ofd_node_to_path(void *mem, ofdn_t p, void *buf, size_t sz)
306 {
307 struct ofd_mem *m = (struct ofd_mem *)mem;
308 struct ofd_node *r = ofd_node_get(m, p);
310 if ( sz > r->on_pathlen ) {
311 sz = r->on_pathlen;
312 }
314 memcpy(buf, r->on_path, sz);
316 if ( r == NULL) return -1;
317 return r->on_pathlen;
318 }
320 static int ofd_check(void *p, size_t l)
321 {
322 int i;
323 u64 *v = (u64 *)p;
325 for ( i = 0; i < l; i++ ) {
326 if ( v[i] != 0ULL ) {
327 return 0;
328 }
329 }
330 return 1;
331 }
335 static ofdn_t ofd_node_create(
336 struct ofd_mem *m, const char *path, size_t pathlen)
337 {
338 struct ofd_node *n;
339 ofdn_t pos;
340 size_t sum = pathlen + 1 + sizeof (*n); /* add trailing zero to path */
341 ofdn_t cells = (sum + sizeof(m->om_mem[0]) - 1) / sizeof(m->om_mem[0]);
343 if ( m->om_next + cells >= m->om_num ) {
344 return 0;
345 }
347 pos = m->om_next;
349 assert(ofd_check(&m->om_mem[pos], cells)); /* non-zero */
350 m->om_next += cells;
352 n = (struct ofd_node *)&m->om_mem[pos];
353 assert(n->on_ima == 0); /* new node not empty */
355 n->on_ima = NODE_PAT;
356 n->on_peer = 0;
357 n->on_child = 0;
358 n->on_io = 0;
359 n->on_pathlen = pathlen;
360 n->on_last = ofd_pathsplit_left(path, '/', pathlen);
361 strlcpy(n->on_path, path, pathlen + 1);
363 return pos;
364 }
366 /* prunes a node and all its children simply by wasting memory and
367 * unlinking it from the tree */
368 int ofd_node_prune(void *mem, ofdn_t node)
369 {
370 struct ofd_mem *m = (struct ofd_mem *)mem;
371 struct ofd_node *n;
372 struct ofd_node *p;
374 n = ofd_node_get(m, node);
375 if (n == NULL) return -1;
377 p = ofd_node_get(m, n->on_parent);
378 assert(p != NULL);
380 if ( p->on_child == node ) {
381 /* easy case */
382 p->on_child = n->on_peer;
383 } else {
384 struct ofd_node *s;
386 s = ofd_node_get(m, p->on_child);
387 assert(s != NULL);
388 while ( s->on_peer != node ) {
389 s = ofd_node_get(m, s->on_peer);
390 assert(s != NULL);
391 }
392 s->on_peer = n->on_peer;
393 }
394 return 1;
395 }
397 ofdn_t ofd_prune_path(void *m, const char *path)
398 {
399 ofdn_t n;
400 int rc = -1;
401 while ((n = ofd_node_find(m, path)) > 0) {
402 rc = ofd_node_prune(m, n);
403 }
405 return rc;
406 }
408 ofdn_t ofd_node_child_create(
409 void *mem, ofdn_t parent, const char *path, size_t pathlen)
410 {
411 struct ofd_mem *m = (struct ofd_mem *)mem;
412 struct ofd_node *p;
413 struct ofd_node *n;
414 ofdn_t pos;
416 p = ofd_node_get(m, parent);
417 if (p == NULL) return 0;
419 pos = ofd_node_create(m, path, pathlen);
420 n = ofd_node_get(m, pos);
421 assert(n != NULL);
423 assert(p->on_child == 0); /* child exists */
424 if ( p->on_child == 0 ) {
425 p->on_child = pos;
426 n->on_parent = parent;
427 } else {
428 pos = 0;
429 }
431 return pos;
432 }
434 ofdn_t ofd_node_peer_create(
435 void *mem, ofdn_t sibling, const char *path, size_t pathlen)
436 {
437 struct ofd_mem *m = (struct ofd_mem *)mem;
438 struct ofd_node *s;
439 struct ofd_node *n;
440 ofdn_t pos;
442 s = ofd_node_get(m, sibling);
443 if (s == NULL) return 0;
445 pos = ofd_node_create(m, path, pathlen);
446 n = ofd_node_get(m, pos);
447 assert(n != NULL);
449 if ( s->on_peer == 0 ) {
450 s->on_peer = pos;
451 n->on_parent = s->on_parent;
452 } else {
453 assert(0); /* peer exists */
454 pos = 0;
455 }
456 return pos;
457 }
459 static ofdn_t ofd_node_peer_last(void *mem, ofdn_t c)
460 {
461 struct ofd_mem *m = (struct ofd_mem *)mem;
462 struct ofd_node *n;
464 n = ofd_node_get(m, c);
465 if (n == NULL) return 0;
467 while ( n->on_peer > 0 ) {
468 c = n->on_peer;
469 n = ofd_node_get(m, c);
470 assert(n != NULL);
471 }
473 return c;
474 }
476 static ofdn_t ofd_node_walk(struct ofd_mem *m, ofdn_t p, const char *s)
477 {
478 struct ofd_node *np;
479 ofdn_t n;
480 ofdn_t r;
482 if ( *s == '/' ) {
483 ++s;
484 if ( *s == '\0' ) {
485 assert(0); /* ends in / */
486 return 0;
487 }
488 }
490 np = ofd_node_get(m, p);
491 if (np == NULL) return 0;
493 r = p;
494 do {
495 int last = np->on_last;
496 size_t lsz = np->on_pathlen - last;
497 size_t sz;
499 sz = ofd_pathsplit_right(s, '/', 0);
501 if ( lsz > 0 && strncmp(s, &np->on_path[last], sz) == 0 ) {
502 if ( s[sz] == '\0' ) {
503 return r;
504 }
505 /* there is more to the path */
506 n = ofd_node_child(m, p);
507 if ( n != 0 ) {
508 r = ofd_node_walk(m, n, &s[sz]);
509 return r;
510 }
511 /* there are no children */
512 return 0;
513 }
514 } while ( 0 );
516 /*
517 * we know that usually we are only serching for top level peers
518 * so we do peers first peer
519 */
520 n = ofd_node_peer(m, p);
521 if ( n > 0 ) {
522 r = ofd_node_walk(m, n, s);
523 } else {
524 r = 0;
525 }
527 return r;
528 }
531 ofdn_t ofd_node_find(void *mem, const char *devspec)
532 {
533 struct ofd_mem *m = (struct ofd_mem *)mem;
534 ofdn_t n = OFD_ROOT;
535 const char *s = devspec;
536 size_t sz;
538 if ( s == NULL || s[0] == '\0' ) {
539 return OFD_ROOT;
540 }
542 if ( s[0] != '/' ) {
543 size_t asz;
545 /* get the component length */
546 sz = ofd_pathsplit_right(s, '/', 0);
548 /* check for an alias */
549 asz = ofd_pathsplit_right(s, ':', sz);
551 if ( s[asz] == ':' ) {
552 /*
553 * s points to an alias and &s[sz] points to the alias
554 * args.
555 */
556 assert(0); /* aliases no supported */
557 return 0;
558 }
559 } else if ( s[1] == '\0' ) {
560 return n;
561 }
563 n = ofd_node_child(m, n);
564 if ( n == 0 ) {
565 return 0;
566 }
568 return ofd_node_walk(m, n, s);
569 }
572 static struct ofd_prop *ofd_prop_get(struct ofd_mem *m, ofdn_t p)
573 {
574 if ( p < m->om_next ) {
575 struct ofd_prop *r;
577 r = (struct ofd_prop *)&m->om_mem[p];
578 if ( r->op_ima == PROP_PAT ) {
579 return r;
580 }
581 assert(r->op_ima == PROP_PAT); /* bad object */
582 }
583 return NULL;
584 }
586 static ofdn_t ofd_prop_create(
587 struct ofd_mem *m,
588 ofdn_t node,
589 const char *name,
590 const void *src,
591 size_t sz)
592 {
593 struct ofd_node *n;
594 struct ofd_prop *p;
595 size_t len = strlen(name) + 1;
596 size_t sum = sizeof (*p) + sz + len;
597 ofdn_t cells;
598 char *dst;
599 ofdn_t pos;
601 cells = (sum + sizeof (m->om_mem[0]) - 1) / sizeof (m->om_mem[0]);
603 if ( m->om_next + cells >= m->om_num ) {
604 return 0;
605 }
607 /* actual data structure */
608 pos = m->om_next;
609 assert(ofd_check(&m->om_mem[pos], cells)); /* non-zero */
611 p = (struct ofd_prop *)&m->om_mem[pos];
612 m->om_next += cells;
614 assert(p->op_ima == 0); /* new node not empty */
615 p->op_ima = PROP_PAT;
616 p->op_next = 0;
617 p->op_objsz = sz;
618 p->op_namesz = len;
620 /* the rest of the data */
621 dst = p->op_data;
623 /* zero what will be the pad, cheap and cannot hurt */
624 m->om_mem[m->om_next - 1] = 0;
626 if ( sz > 0 ) {
627 /* some props have no data, just a name */
628 memcpy(dst, src, sz);
629 dst += sz;
630 }
632 memcpy(dst, name, len);
634 /* now place it in the tree */
635 n = ofd_node_get(m, node);
636 assert(n != NULL);
638 if ( n->on_prop == 0 ) {
639 n->on_prop = pos;
640 } else {
641 ofdn_t pn = n->on_prop;
642 struct ofd_prop *nxt;
644 for (;;) {
645 nxt = ofd_prop_get(m, pn);
646 if (nxt->op_next == 0) {
647 nxt->op_next = pos;
648 break;
649 }
650 pn = nxt->op_next;
651 }
652 }
654 return pos;
655 }
657 void ofd_prop_remove(void *mem, ofdn_t node, ofdn_t prop)
658 {
659 struct ofd_mem *m = (struct ofd_mem *)mem;
660 struct ofd_node *n = ofd_node_get(m, node);
661 struct ofd_prop *p = ofd_prop_get(m, prop);
663 if (n == NULL) return;
664 if (p == NULL) return;
666 if ( n->on_prop == prop ) {
667 n->on_prop = p->op_next;
668 } else {
669 ofdn_t pn = n->on_prop;
670 struct ofd_prop *nxt;
672 for ( ; ; ) {
673 nxt = ofd_prop_get(m, pn);
674 if ( nxt->op_next == prop ) {
675 nxt->op_next = p->op_next;
676 break;
677 }
678 pn = nxt->op_next;
679 }
680 }
681 return;
682 }
684 ofdn_t ofd_prop_find(void *mem, ofdn_t n, const char *name)
685 {
686 struct ofd_mem *m = (struct ofd_mem *)mem;
687 ofdn_t p = ofd_node_prop(m, n);
688 struct ofd_prop *r;
689 char *s;
690 size_t len;
692 if ( name == NULL || *name == '\0' ) {
693 return OFD_ROOT;
694 }
696 len = strlen(name) + 1;
698 while ( p != 0 ) {
699 r = ofd_prop_get(m, p);
700 s = &r->op_data[r->op_objsz];
701 if ( len == r->op_namesz ) {
702 if ( strncmp(name, s, r->op_namesz) == 0 ) {
703 break;
704 }
705 }
706 p = r->op_next;
707 }
708 return p;
709 }
711 static ofdn_t ofd_prop_next(struct ofd_mem *m, ofdn_t n, const char *prev)
712 {
713 ofdn_t p;
715 if ( prev == NULL || *prev == '\0' ) {
716 /* give the first */
717 p = ofd_node_prop(m, n);
718 } else {
719 struct ofd_prop *r;
721 /* look for the name */
722 p = ofd_prop_find(m, n, prev);
723 if ( p != 0 ) {
724 /* get the data for prev */
725 r = ofd_prop_get(m, p);
727 /* now get next */
728 p = r->op_next;
729 } else {
730 p = -1;
731 }
732 }
734 return p;
735 }
737 ofdn_t ofd_nextprop(void *mem, ofdn_t n, const char *prev, char *name)
738 {
739 struct ofd_mem *m = (struct ofd_mem *)mem;
740 ofdn_t p = ofd_prop_next(m, n, prev);
741 struct ofd_prop *r;
742 char *s;
744 if ( p > 0 ) {
745 r = ofd_prop_get(m, p);
746 s = &r->op_data[r->op_objsz];
747 memcpy(name, s, r->op_namesz);
748 }
750 return p;
751 }
753 /*
754 * It is valid to call with NULL pointers, in case you want only one
755 * cell size.
756 */
757 int ofd_getcells(void* mem, ofdn_t n, u32* addr_cells, u32* size_cells)
758 {
759 if ( addr_cells != NULL ) *addr_cells = 0;
760 if ( size_cells != NULL ) *size_cells = 0;
762 retry:
763 if ( addr_cells != NULL && *addr_cells == 0 ) {
764 ofd_getprop(mem, n, "#address-cells",
765 addr_cells, sizeof(u32));
766 }
768 if ( size_cells != NULL && *size_cells == 0 ) {
769 ofd_getprop(mem, n, "#size-cells", size_cells, sizeof(u32));
770 }
772 if ( ( size_cells != NULL && *size_cells == 0 )
773 || ( addr_cells != NULL && *addr_cells == 0 ) ) {
774 if ( n != OFD_ROOT ) {
775 n = ofd_node_parent(mem, n);
776 goto retry;
777 }
778 return -1;
779 }
781 return 1;
782 }
784 int ofd_getprop(void *mem, ofdn_t n, const char *name, void *buf, size_t sz)
785 {
786 struct ofd_mem *m = (struct ofd_mem *)mem;
787 ofdn_t p = ofd_prop_find(m, n, name);
788 struct ofd_prop *r;
790 if ( p == 0 ) {
791 return -1;
792 }
794 r = ofd_prop_get(m, p);
796 if ( sz > r->op_objsz ) {
797 sz = r->op_objsz;
798 }
799 memcpy(buf, r->op_data, sz);
801 return r->op_objsz;
802 }
804 int ofd_getproplen(void *mem, ofdn_t n, const char *name)
805 {
806 struct ofd_mem *m = (struct ofd_mem *)mem;
807 ofdn_t p = ofd_prop_find(m, n, name);
808 struct ofd_prop *r;
810 if ( p == 0 ) {
811 return -1;
812 }
814 r = ofd_prop_get(m, p);
816 return r->op_objsz;
817 }
819 static ofdn_t ofd_prop_set(
820 void *mem, ofdn_t n, const char *name, const void *src, size_t sz)
821 {
822 struct ofd_mem *m = (struct ofd_mem *)mem;
823 ofdn_t p = ofd_prop_find(m, n, name);
824 struct ofd_prop *r;
825 char *dst;
827 r = ofd_prop_get(m, p);
829 if ( sz <= r->op_objsz ) {
830 /* we can reuse */
831 memcpy(r->op_data, src, sz);
832 if ( sz < r->op_objsz ) {
833 /* need to move name */
834 dst = r->op_data + sz;
835 /*
836 * use the name arg size we may have overlap with the
837 * original
838 */
839 memcpy(dst, name, r->op_namesz);
840 r->op_objsz = sz;
841 }
842 } else {
843 /*
844 * Sadly, we remove from the list, wasting the space and then
845 * we can creat a new one
846 */
847 ofd_prop_remove(m, n, p);
848 p = ofd_prop_create(mem, n, name, src, sz);
849 }
851 return p;
852 }
854 int ofd_setprop(
855 void *mem, ofdn_t n, const char *name, const void *buf, size_t sz)
856 {
857 struct ofd_mem *m = (struct ofd_mem *)mem;
858 ofdn_t r;
860 r = ofd_prop_find(m, n, name);
861 if ( r == 0 ) {
862 r = ofd_prop_create(mem, n, name, buf, sz);
863 } else {
864 r = ofd_prop_set(mem, n, name, buf, sz);
865 }
867 if ( r > 0 ) {
868 struct ofd_prop *pp = ofd_prop_get(m, r);
869 return pp->op_objsz;
870 }
872 return OF_FAILURE;
873 }
876 static ofdn_t ofd_find_by_prop(
877 struct ofd_mem *m,
878 ofdn_t head,
879 ofdn_t *prev_p,
880 ofdn_t n,
881 const char *name,
882 const void *val,
883 size_t sz)
884 {
885 struct ofd_node *np;
886 struct ofd_prop *pp;
887 ofdn_t p;
889 retry:
890 p = ofd_prop_find(m, n, name);
892 if ( p > 0 ) {
893 int match = 0;
895 /* a property exists by that name */
896 if ( val == NULL ) {
897 match = 1;
898 } else {
899 /* need to compare values */
900 pp = ofd_prop_get(m, p);
901 if ( sz == pp->op_objsz
902 && memcmp(pp->op_data, val, sz) == 0 ) {
903 match = 1;
904 }
905 }
906 if ( match == 1 ) {
907 if ( *prev_p >= 0 ) {
908 np = ofd_node_get(m, *prev_p);
909 np->on_next = n;
910 } else {
911 head = n;
912 }
913 np = ofd_node_get(m, n);
914 np->on_prev = *prev_p;
915 np->on_next = -1;
916 *prev_p = n;
917 }
918 }
920 p = ofd_node_child(m, n);
921 if ( p > 0 ) {
922 head = ofd_find_by_prop(m, head, prev_p, p, name, val, sz);
923 }
925 p = ofd_node_peer(m, n);
926 if ( p > 0 ) {
927 n = p;
928 goto retry;
929 }
931 return head;
932 }
934 ofdn_t ofd_node_find_by_prop(
935 void *mem,
936 ofdn_t n,
937 const char *name,
938 const void *val,
939 size_t sz)
940 {
941 struct ofd_mem *m = (struct ofd_mem *)mem;
943 if ( n <= 0 ) {
944 n = OFD_ROOT;
945 }
947 ofdn_t prev = -1;
948 return ofd_find_by_prop(m, -1, &prev, n, name, val, sz);
949 }
951 ofdn_t ofd_node_find_next(void *mem, ofdn_t n)
952 {
953 struct ofd_mem *m = (struct ofd_mem *)mem;
954 struct ofd_node *np;
956 np = ofd_node_get(m, n);
958 if (np == NULL) return 0;
959 return np->on_next;
960 }
962 ofdn_t ofd_node_find_prev(void *mem, ofdn_t n)
963 {
964 struct ofd_mem *m = (struct ofd_mem *)mem;
965 struct ofd_node *np;
967 np = ofd_node_get(m, n);
968 if (np == NULL) return 0;
970 return np->on_prev;
971 }
973 ofdn_t ofd_io_create(void *mem, ofdn_t node, u64 open)
974 {
975 struct ofd_mem *m = (struct ofd_mem *)mem;
976 struct ofd_node *n;
977 struct ofd_io *i;
978 ofdn_t pos;
979 ofdn_t cells;
981 cells = (sizeof (*i) + sizeof (m->om_mem[0]) - 1) / sizeof(m->om_mem[0]);
983 n = ofd_node_get(m, node);
984 if ( n == NULL ) return 0;
986 if ( m->om_next + cells >= m->om_num ) {
987 return 0;
988 }
990 pos = m->om_next;
991 assert(ofd_check(&m->om_mem[pos], cells)); /* non-zero */
993 m->om_next += cells;
995 i = (struct ofd_io *)&m->om_mem[pos];
996 assert(i->oi_ima == 0); /* new node not empty */
998 i->oi_ima = IO_PAT;
999 i->oi_node = node;
1000 i->oi_open = open;
1002 n->on_io = pos;
1004 return pos;
1007 static struct ofd_io *ofd_io_get(struct ofd_mem *m, ofdn_t i)
1009 if ( i < m->om_next ) {
1010 struct ofd_io *r;
1012 r = (struct ofd_io *)&m->om_mem[i];
1013 if ( r->oi_ima == IO_PAT ) {
1014 return r;
1016 assert(r->oi_ima == IO_PAT); /* bad object */
1019 return NULL;
1022 ofdn_t ofd_node_io(void *mem, ofdn_t n)
1024 struct ofd_mem *m = (struct ofd_mem *)mem;
1025 struct ofd_node *r = ofd_node_get(m, n);
1027 if (r == NULL) return 0;
1028 return r->on_io;
1031 uint ofd_io_open(void *mem, ofdn_t n)
1033 struct ofd_mem *m = (struct ofd_mem *)mem;
1034 struct ofd_io *r = ofd_io_get(m, n);
1036 if (r == NULL) return 0;
1037 return r->oi_open;
1040 void ofd_io_close(void *mem, ofdn_t n)
1042 struct ofd_mem *m = (struct ofd_mem *)mem;
1043 struct ofd_io *o = ofd_io_get(m, n);
1044 struct ofd_node *r = ofd_node_get(m, o->oi_node);
1046 assert(o != NULL);
1047 assert(r != NULL);
1048 o->oi_open = 0;
1049 r->on_io = 0;
1052 ofdn_t ofd_node_add(void *m, ofdn_t p, const char *path, size_t sz)
1054 ofdn_t n;
1056 n = ofd_node_child(m, p);
1057 if ( n > 0 ) {
1058 n = ofd_node_peer_last(m, n);
1059 if ( n > 0 ) {
1060 n = ofd_node_peer_create(m, n, path, sz);
1062 } else {
1063 n = ofd_node_child_create(m, p, path, sz);
1066 return n;
1069 ofdn_t ofd_prop_add(
1070 void *mem,
1071 ofdn_t n,
1072 const char *name,
1073 const void *buf,
1074 size_t sz)
1076 struct ofd_mem *m = (struct ofd_mem *)mem;
1077 ofdn_t r;
1079 r = ofd_prop_find(m, n, name);
1080 if ( r == 0 ) {
1081 r = ofd_prop_create(mem, n, name, buf, sz);
1082 } else {
1083 r = ofd_prop_set(mem, n, name, buf, sz);
1086 return r;