2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * prof_tree.c --- these routines maintain the parse tree of the
11 * All of the details of how the tree is stored is abstracted away in
12 * this file; all of the other profile routines build, access, and
13 * modify the tree via the accessor functions found in this file.
15 * Each node may represent either a relation or a section header.
17 * A section header must have its value field set to 0, and may a one
18 * or more child nodes, pointed to by first_child.
20 * A relation has as its value a pointer to allocated memory
21 * containing a string. Its first_child pointer must be null.
41 int final
:1; /* Indicate don't search next file */
43 struct profile_node
*first_child
;
44 struct profile_node
*parent
;
45 struct profile_node
*next
, *prev
;
48 #define CHECK_MAGIC(node) \
49 if ((node)->magic != PROF_MAGIC_NODE) \
50 return PROF_MAGIC_NODE;
53 * Free a node, and any children
55 void profile_free_node(struct profile_node
*node
)
57 struct profile_node
*child
, *next
;
59 if (node
->magic
!= PROF_MAGIC_NODE
)
65 for (child
=node
->first_child
; child
; child
= next
) {
67 profile_free_node(child
);
76 #define strdup MYstrdup
77 static char *MYstrdup (const char *s
)
79 size_t sz
= strlen(s
) + 1;
90 errcode_t
profile_create_node(const char *name
, const char *value
,
91 struct profile_node
**ret_node
)
93 struct profile_node
*new;
95 new = malloc(sizeof(struct profile_node
));
98 memset(new, 0, sizeof(struct profile_node
));
99 new->name
= strdup(name
);
100 if (new->name
== 0) {
101 profile_free_node(new);
105 new->value
= strdup(value
);
106 if (new->value
== 0) {
107 profile_free_node(new);
111 new->magic
= PROF_MAGIC_NODE
;
118 * This function verifies that all of the representation invarients of
119 * the profile are true. If not, we have a programming bug somewhere,
120 * probably in this file.
122 errcode_t
profile_verify_node(struct profile_node
*node
)
124 struct profile_node
*p
, *last
;
129 if (node
->value
&& node
->first_child
)
130 return PROF_SECTION_WITH_VALUE
;
133 for (p
= node
->first_child
; p
; last
= p
, p
= p
->next
) {
135 return PROF_BAD_LINK_LIST
;
136 if (last
&& (last
->next
!= p
))
137 return PROF_BAD_LINK_LIST
;
138 if (node
->group_level
+1 != p
->group_level
)
139 return PROF_BAD_GROUP_LVL
;
140 if (p
->parent
!= node
)
141 return PROF_BAD_PARENT_PTR
;
142 retval
= profile_verify_node(p
);
150 * Add a node to a particular section
152 errcode_t
profile_add_node(struct profile_node
*section
, const char *name
,
153 const char *value
, struct profile_node
**ret_node
)
156 struct profile_node
*p
, *last
, *new;
158 CHECK_MAGIC(section
);
161 return PROF_ADD_NOT_SECTION
;
164 * Find the place to insert the new node. We look for the
165 * place *after* the last match of the node name, since
168 for (p
=section
->first_child
, last
= 0; p
; last
= p
, p
= p
->next
) {
170 cmp
= strcmp(p
->name
, name
);
174 retval
= profile_create_node(name
, value
, &new);
177 new->group_level
= section
->group_level
+1;
179 new->parent
= section
;
187 section
->first_child
= new;
194 * Set the final flag on a particular node.
196 errcode_t
profile_make_node_final(struct profile_node
*node
)
205 * Check the final flag on a node
207 int profile_is_node_final(struct profile_node
*node
)
209 return (node
->final
!= 0);
213 * Return the name of a node. (Note: this is for internal functions
214 * only; if the name needs to be returned from an exported function,
217 const char *profile_get_node_name(struct profile_node
*node
)
223 * Return the value of a node. (Note: this is for internal functions
224 * only; if the name needs to be returned from an exported function,
227 const char *profile_get_node_value(struct profile_node
*node
)
233 * Iterate through the section, returning the nodes which match
234 * the given name. If name is NULL, then interate through all the
235 * nodes in the section. If section_flag is non-zero, only return the
236 * section which matches the name; don't return relations. If value
237 * is non-NULL, then only return relations which match the requested
238 * value. (The value argument is ignored if section_flag is non-zero.)
240 * The first time this routine is called, the state pointer must be
241 * null. When this profile_find_node_relation() returns, if the state
242 * pointer is non-NULL, then this routine should be called again.
243 * (This won't happen if section_flag is non-zero, obviously.)
246 errcode_t
profile_find_node(struct profile_node
*section
, const char *name
,
247 const char *value
, int section_flag
, void **state
,
248 struct profile_node
**node
)
250 struct profile_node
*p
;
252 CHECK_MAGIC(section
);
257 p
= section
->first_child
;
259 for (; p
; p
= p
->next
) {
260 if (name
&& (strcmp(p
->name
, name
)))
268 if (value
&& (strcmp(p
->value
, value
)))
280 return section_flag
? PROF_NO_SECTION
: PROF_NO_RELATION
;
283 * OK, we've found one match; now let's try to find another
284 * one. This way, if we return a non-zero state pointer,
285 * there's guaranteed to be another match that's returned.
287 for (p
= p
->next
; p
; p
= p
->next
) {
288 if (name
&& (strcmp(p
->name
, name
)))
296 if (value
&& (strcmp(p
->value
, value
)))
308 * Iterate through the section, returning the relations which match
309 * the given name. If name is NULL, then interate through all the
310 * relations in the section. The first time this routine is called,
311 * the state pointer must be null. When this profile_find_node_relation()
312 * returns, if the state pointer is non-NULL, then this routine should
315 * The returned character string in value points to the stored
316 * character string in the parse string. Before this string value is
317 * returned to a calling application (profile_find_node_relation is not an
318 * exported interface), it should be strdup()'ed.
320 errcode_t
profile_find_node_relation(struct profile_node
*section
,
321 const char *name
, void **state
,
322 char **ret_name
, char **value
)
324 struct profile_node
*p
;
327 retval
= profile_find_node(section
, name
, 0, 0, state
, &p
);
341 * Iterate through the section, returning the subsections which match
342 * the given name. If name is NULL, then interate through all the
343 * subsections in the section. The first time this routine is called,
344 * the state pointer must be null. When this profile_find_node_subsection()
345 * returns, if the state pointer is non-NULL, then this routine should
348 * This is (plus accessor functions for the name and value given a
349 * profile node) makes this function mostly syntactic sugar for
352 errcode_t
profile_find_node_subsection(struct profile_node
*section
,
353 const char *name
, void **state
,
355 struct profile_node
**subsection
)
357 struct profile_node
*p
;
360 /* Solaris Kerberos */
362 return (PROF_NO_PROFILE
);
364 retval
= profile_find_node(section
, name
, 0, 1, state
, &p
);
378 * This function returns the parent of a particular node.
380 errcode_t
profile_get_node_parent(struct profile_node
*section
,
381 struct profile_node
**parent
)
383 *parent
= section
->parent
;
388 * This is a general-purpose iterator for returning all nodes that
389 * match the specified name array.
391 struct profile_iterator
{
395 const char *const *names
;
400 struct profile_node
*node
;
404 errcode_t
profile_node_iterator_create(profile_t profile
,
405 const char *const *names
, int flags
,
408 struct profile_iterator
*iter
;
412 return PROF_NO_PROFILE
;
413 if (profile
->magic
!= PROF_MAGIC_PROFILE
)
414 return PROF_MAGIC_PROFILE
;
416 return PROF_BAD_NAMESET
;
417 if (!(flags
& PROFILE_ITER_LIST_SECTION
)) {
419 return PROF_BAD_NAMESET
;
423 if ((iter
= malloc(sizeof(struct profile_iterator
))) == NULL
)
426 iter
->magic
= PROF_MAGIC_ITERATOR
;
427 iter
->profile
= profile
;
430 iter
->file
= profile
->first_file
;
431 iter
->done_idx
= done_idx
;
438 void profile_node_iterator_free(void **iter_p
)
440 struct profile_iterator
*iter
;
445 if (!iter
|| iter
->magic
!= PROF_MAGIC_ITERATOR
)
452 * Note: the returned character strings in ret_name and ret_value
453 * points to the stored character string in the parse string. Before
454 * this string value is returned to a calling application
455 * (profile_node_iterator is not an exported interface), it should be
458 errcode_t
profile_node_iterator(void **iter_p
, struct profile_node
**ret_node
,
459 char **ret_name
, char **ret_value
)
461 struct profile_iterator
*iter
= *iter_p
;
462 struct profile_node
*section
, *p
;
463 const char *const *cpp
;
467 if (!iter
|| iter
->magic
!= PROF_MAGIC_ITERATOR
)
468 return PROF_MAGIC_ITERATOR
;
469 if (iter
->file
&& iter
->file
->magic
!= PROF_MAGIC_FILE
)
470 return PROF_MAGIC_FILE
;
471 if (iter
->file
&& iter
->file
->data
->magic
!= PROF_MAGIC_FILE_DATA
)
472 return PROF_MAGIC_FILE_DATA
;
474 * If the file has changed, then the node pointer is invalid,
475 * so we'll have search the file again looking for it.
478 retval
= k5_mutex_lock(&iter
->file
->data
->lock
);
482 if (iter
->node
&& (iter
->file
->data
->upd_serial
!= iter
->file_serial
)) {
483 iter
->flags
&= ~PROFILE_ITER_FINAL_SEEN
;
484 skip_num
= iter
->num
;
487 if (iter
->node
&& iter
->node
->magic
!= PROF_MAGIC_NODE
) {
489 k5_mutex_unlock(&iter
->file
->data
->lock
);
490 return PROF_MAGIC_NODE
;
493 if (iter
->node
== 0) {
494 if (iter
->file
== 0 ||
495 (iter
->flags
& PROFILE_ITER_FINAL_SEEN
)) {
497 k5_mutex_unlock(&iter
->file
->data
->lock
);
498 profile_node_iterator_free(iter_p
);
507 k5_mutex_unlock(&iter
->file
->data
->lock
);
508 if ((retval
= profile_update_file(iter
->file
))) {
509 if (retval
== ENOENT
|| retval
== EACCES
) {
510 /* XXX memory leak? */
511 iter
->file
= iter
->file
->next
;
513 retval
= k5_mutex_lock(&iter
->file
->data
->lock
);
515 profile_node_iterator_free(iter_p
);
523 profile_node_iterator_free(iter_p
);
527 retval
= k5_mutex_lock(&iter
->file
->data
->lock
);
529 profile_node_iterator_free(iter_p
);
532 iter
->file_serial
= iter
->file
->data
->upd_serial
;
534 * Find the section to list if we are a LIST_SECTION,
535 * or find the containing section if not.
537 section
= iter
->file
->data
->root
;
538 assert(section
!= NULL
);
539 for (cpp
= iter
->names
; cpp
[iter
->done_idx
]; cpp
++) {
540 for (p
=section
->first_child
; p
; p
= p
->next
) {
541 if (!strcmp(p
->name
, *cpp
) && !p
->value
)
550 iter
->flags
|= PROFILE_ITER_FINAL_SEEN
;
553 k5_mutex_unlock(&iter
->file
->data
->lock
);
554 iter
->file
= iter
->file
->next
;
556 retval
= k5_mutex_lock(&iter
->file
->data
->lock
);
558 profile_node_iterator_free(iter_p
);
566 iter
->node
= section
->first_child
;
569 * OK, now we know iter->node is set up correctly. Let's do
572 for (p
= iter
->node
; p
; p
= p
->next
) {
573 if (iter
->name
&& strcmp(p
->name
, iter
->name
))
575 if ((iter
->flags
& PROFILE_ITER_SECTIONS_ONLY
) &&
578 if ((iter
->flags
& PROFILE_ITER_RELATIONS_ONLY
) &&
591 k5_mutex_unlock(&iter
->file
->data
->lock
);
592 iter
->file
= iter
->file
->next
;
594 retval
= k5_mutex_lock(&iter
->file
->data
->lock
);
596 profile_node_iterator_free(iter_p
);
604 k5_mutex_unlock(&iter
->file
->data
->lock
);
605 if ((iter
->node
= p
->next
) == NULL
)
606 iter
->file
= iter
->file
->next
;
612 *ret_value
= p
->value
;
617 * Remove a particular node.
621 errcode_t
profile_remove_node(struct profile_node
*node
)
625 if (node
->parent
== 0)
626 return PROF_EINVAL
; /* Can't remove the root! */
634 * Set the value of a specific node containing a relation.
638 errcode_t
profile_set_relation_value(struct profile_node
*node
,
639 const char *new_value
)
646 return PROF_SET_SECTION_VALUE
;
648 cp
= malloc(strlen(new_value
)+1);
652 strcpy(cp
, new_value
);
660 * Rename a specific node
664 errcode_t
profile_rename_node(struct profile_node
*node
, const char *new_name
)
667 struct profile_node
*p
, *last
;
671 if (strcmp(new_name
, node
->name
) == 0)
672 return 0; /* It's the same name, return */
675 * Make sure we can allocate memory for the new name, first!
677 new_string
= malloc(strlen(new_name
)+1);
680 strcpy(new_string
, new_name
);
683 * Find the place to where the new node should go. We look
684 * for the place *after* the last match of the node name,
685 * since order matters.
687 for (p
=node
->parent
->first_child
, last
= 0; p
; last
= p
, p
= p
->next
) {
688 if (strcmp(p
->name
, new_name
) > 0)
693 * If we need to move the node, do it now.
695 if ((p
!= node
) && (last
!= node
)) {
697 * OK, let's detach the node
700 node
->prev
->next
= node
->next
;
702 node
->parent
->first_child
= node
->next
;
704 node
->next
->prev
= node
->prev
;
707 * Now let's reattach it in the right place.
714 node
->parent
->first_child
= node
;
720 node
->name
= new_string
;