17c478bd9Sstevel@tonic-gate /* 2*505d05c7Sgtb * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate /* 97c478bd9Sstevel@tonic-gate * prof_tree.c --- these routines maintain the parse tree of the 107c478bd9Sstevel@tonic-gate * config file. 11*505d05c7Sgtb * 127c478bd9Sstevel@tonic-gate * All of the details of how the tree is stored is abstracted away in 137c478bd9Sstevel@tonic-gate * this file; all of the other profile routines build, access, and 147c478bd9Sstevel@tonic-gate * modify the tree via the accessor functions found in this file. 157c478bd9Sstevel@tonic-gate * 167c478bd9Sstevel@tonic-gate * Each node may represent either a relation or a section header. 17*505d05c7Sgtb * 187c478bd9Sstevel@tonic-gate * A section header must have its value field set to 0, and may a one 197c478bd9Sstevel@tonic-gate * or more child nodes, pointed to by first_child. 20*505d05c7Sgtb * 217c478bd9Sstevel@tonic-gate * A relation has as its value a pointer to allocated memory 227c478bd9Sstevel@tonic-gate * containing a string. Its first_child pointer must be null. 237c478bd9Sstevel@tonic-gate * 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 26*505d05c7Sgtb 27*505d05c7Sgtb #include "prof_int.h" 28*505d05c7Sgtb 297c478bd9Sstevel@tonic-gate #include <stdio.h> 307c478bd9Sstevel@tonic-gate #include <string.h> 317c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H 327c478bd9Sstevel@tonic-gate #include <stdlib.h> 337c478bd9Sstevel@tonic-gate #endif 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <ctype.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate struct profile_node { 387c478bd9Sstevel@tonic-gate errcode_t magic; 397c478bd9Sstevel@tonic-gate char *name; 407c478bd9Sstevel@tonic-gate char *value; 417c478bd9Sstevel@tonic-gate int group_level; 427c478bd9Sstevel@tonic-gate int final:1; /* Indicate don't search next file */ 43*505d05c7Sgtb int deleted:1; 447c478bd9Sstevel@tonic-gate struct profile_node *first_child; 457c478bd9Sstevel@tonic-gate struct profile_node *parent; 467c478bd9Sstevel@tonic-gate struct profile_node *next, *prev; 477c478bd9Sstevel@tonic-gate }; 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define CHECK_MAGIC(node) \ 507c478bd9Sstevel@tonic-gate if ((node)->magic != PROF_MAGIC_NODE) \ 517c478bd9Sstevel@tonic-gate return PROF_MAGIC_NODE; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * Free a node, and any children 557c478bd9Sstevel@tonic-gate */ 56*505d05c7Sgtb void profile_free_node(struct profile_node *node) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate struct profile_node *child, *next; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate if (node->magic != PROF_MAGIC_NODE) 617c478bd9Sstevel@tonic-gate return; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate if (node->name) 647c478bd9Sstevel@tonic-gate free(node->name); 657c478bd9Sstevel@tonic-gate if (node->value) 667c478bd9Sstevel@tonic-gate free(node->value); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate for (child=node->first_child; child; child = next) { 697c478bd9Sstevel@tonic-gate next = child->next; 707c478bd9Sstevel@tonic-gate profile_free_node(child); 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate node->magic = 0; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate free(node); 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 77*505d05c7Sgtb #ifndef HAVE_STRDUP 78*505d05c7Sgtb #undef strdup 79*505d05c7Sgtb #define strdup MYstrdup 80*505d05c7Sgtb static char *MYstrdup (const char *s) 81*505d05c7Sgtb { 82*505d05c7Sgtb size_t sz = strlen(s) + 1; 83*505d05c7Sgtb char *p = malloc(sz); 84*505d05c7Sgtb if (p != 0) 85*505d05c7Sgtb memcpy(p, s, sz); 86*505d05c7Sgtb return p; 87*505d05c7Sgtb } 88*505d05c7Sgtb #endif 89*505d05c7Sgtb 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Create a node 927c478bd9Sstevel@tonic-gate */ 93*505d05c7Sgtb errcode_t profile_create_node(const char *name, const char *value, 94*505d05c7Sgtb struct profile_node **ret_node) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate struct profile_node *new; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate new = (struct profile_node *)malloc(sizeof(struct profile_node)); 997c478bd9Sstevel@tonic-gate if (!new) 1007c478bd9Sstevel@tonic-gate return ENOMEM; 1017c478bd9Sstevel@tonic-gate memset(new, 0, sizeof(struct profile_node)); 102*505d05c7Sgtb new->name = (char *) strdup(name); 1037c478bd9Sstevel@tonic-gate if (new->name == 0) { 104*505d05c7Sgtb profile_free_node(new); 105*505d05c7Sgtb return ENOMEM; 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate if (value) { 108*505d05c7Sgtb new->value = (char *) strdup(value); 1097c478bd9Sstevel@tonic-gate if (new->value == 0) { 110*505d05c7Sgtb profile_free_node(new); 111*505d05c7Sgtb return ENOMEM; 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate new->magic = PROF_MAGIC_NODE; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate *ret_node = new; 1177c478bd9Sstevel@tonic-gate return 0; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * This function verifies that all of the representation invarients of 1227c478bd9Sstevel@tonic-gate * the profile are true. If not, we have a programming bug somewhere, 1237c478bd9Sstevel@tonic-gate * probably in this file. 1247c478bd9Sstevel@tonic-gate */ 125*505d05c7Sgtb errcode_t profile_verify_node(struct profile_node *node) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate struct profile_node *p, *last; 1287c478bd9Sstevel@tonic-gate errcode_t retval; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate if (node->value && node->first_child) 1337c478bd9Sstevel@tonic-gate return PROF_SECTION_WITH_VALUE; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate last = 0; 1367c478bd9Sstevel@tonic-gate for (p = node->first_child; p; last = p, p = p->next) { 1377c478bd9Sstevel@tonic-gate if (p->prev != last) 1387c478bd9Sstevel@tonic-gate return PROF_BAD_LINK_LIST; 1397c478bd9Sstevel@tonic-gate if (last && (last->next != p)) 1407c478bd9Sstevel@tonic-gate return PROF_BAD_LINK_LIST; 1417c478bd9Sstevel@tonic-gate if (node->group_level+1 != p->group_level) 1427c478bd9Sstevel@tonic-gate return PROF_BAD_GROUP_LVL; 1437c478bd9Sstevel@tonic-gate if (p->parent != node) 1447c478bd9Sstevel@tonic-gate return PROF_BAD_PARENT_PTR; 1457c478bd9Sstevel@tonic-gate retval = profile_verify_node(p); 1467c478bd9Sstevel@tonic-gate if (retval) 1477c478bd9Sstevel@tonic-gate return retval; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate return 0; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * Add a node to a particular section 1547c478bd9Sstevel@tonic-gate */ 155*505d05c7Sgtb errcode_t profile_add_node(struct profile_node *section, const char *name, 156*505d05c7Sgtb const char *value, struct profile_node **ret_node) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate errcode_t retval; 1597c478bd9Sstevel@tonic-gate struct profile_node *p, *last, *new; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate CHECK_MAGIC(section); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if (section->value) 1647c478bd9Sstevel@tonic-gate return PROF_ADD_NOT_SECTION; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * Find the place to insert the new node. We look for the 168*505d05c7Sgtb * place *after* the last match of the node name, since 1697c478bd9Sstevel@tonic-gate * order matters. 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate for (p=section->first_child, last = 0; p; last = p, p = p->next) { 172*505d05c7Sgtb int cmp; 1737c478bd9Sstevel@tonic-gate cmp = strcmp(p->name, name); 1747c478bd9Sstevel@tonic-gate if (cmp > 0) 1757c478bd9Sstevel@tonic-gate break; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate retval = profile_create_node(name, value, &new); 1787c478bd9Sstevel@tonic-gate if (retval) 1797c478bd9Sstevel@tonic-gate return retval; 1807c478bd9Sstevel@tonic-gate new->group_level = section->group_level+1; 181*505d05c7Sgtb new->deleted = 0; 1827c478bd9Sstevel@tonic-gate new->parent = section; 1837c478bd9Sstevel@tonic-gate new->prev = last; 1847c478bd9Sstevel@tonic-gate new->next = p; 1857c478bd9Sstevel@tonic-gate if (p) 1867c478bd9Sstevel@tonic-gate p->prev = new; 1877c478bd9Sstevel@tonic-gate if (last) 1887c478bd9Sstevel@tonic-gate last->next = new; 1897c478bd9Sstevel@tonic-gate else 1907c478bd9Sstevel@tonic-gate section->first_child = new; 1917c478bd9Sstevel@tonic-gate if (ret_node) 1927c478bd9Sstevel@tonic-gate *ret_node = new; 1937c478bd9Sstevel@tonic-gate return 0; 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Set the final flag on a particular node. 1987c478bd9Sstevel@tonic-gate */ 199*505d05c7Sgtb errcode_t profile_make_node_final(struct profile_node *node) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate node->final = 1; 2047c478bd9Sstevel@tonic-gate return 0; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Check the final flag on a node 2097c478bd9Sstevel@tonic-gate */ 210*505d05c7Sgtb int profile_is_node_final(struct profile_node *node) 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate return (node->final != 0); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Return the name of a node. (Note: this is for internal functions 2177c478bd9Sstevel@tonic-gate * only; if the name needs to be returned from an exported function, 2187c478bd9Sstevel@tonic-gate * strdup it first!) 2197c478bd9Sstevel@tonic-gate */ 220*505d05c7Sgtb const char *profile_get_node_name(struct profile_node *node) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate return node->name; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * Return the value of a node. (Note: this is for internal functions 2277c478bd9Sstevel@tonic-gate * only; if the name needs to be returned from an exported function, 2287c478bd9Sstevel@tonic-gate * strdup it first!) 2297c478bd9Sstevel@tonic-gate */ 230*505d05c7Sgtb const char *profile_get_node_value(struct profile_node *node) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate return node->value; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Iterate through the section, returning the nodes which match 2377c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 2387c478bd9Sstevel@tonic-gate * nodes in the section. If section_flag is non-zero, only return the 2397c478bd9Sstevel@tonic-gate * section which matches the name; don't return relations. If value 2407c478bd9Sstevel@tonic-gate * is non-NULL, then only return relations which match the requested 2417c478bd9Sstevel@tonic-gate * value. (The value argument is ignored if section_flag is non-zero.) 242*505d05c7Sgtb * 2437c478bd9Sstevel@tonic-gate * The first time this routine is called, the state pointer must be 2447c478bd9Sstevel@tonic-gate * null. When this profile_find_node_relation() returns, if the state 2457c478bd9Sstevel@tonic-gate * pointer is non-NULL, then this routine should be called again. 2467c478bd9Sstevel@tonic-gate * (This won't happen if section_flag is non-zero, obviously.) 2477c478bd9Sstevel@tonic-gate * 2487c478bd9Sstevel@tonic-gate */ 249*505d05c7Sgtb errcode_t profile_find_node(struct profile_node *section, const char *name, 250*505d05c7Sgtb const char *value, int section_flag, void **state, 251*505d05c7Sgtb struct profile_node **node) 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate struct profile_node *p; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate CHECK_MAGIC(section); 2567c478bd9Sstevel@tonic-gate p = *state; 2577c478bd9Sstevel@tonic-gate if (p) { 2587c478bd9Sstevel@tonic-gate CHECK_MAGIC(p); 2597c478bd9Sstevel@tonic-gate } else 2607c478bd9Sstevel@tonic-gate p = section->first_child; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate for (; p; p = p->next) { 2637c478bd9Sstevel@tonic-gate if (name && (strcmp(p->name, name))) 2647c478bd9Sstevel@tonic-gate continue; 2657c478bd9Sstevel@tonic-gate if (section_flag) { 2667c478bd9Sstevel@tonic-gate if (p->value) 2677c478bd9Sstevel@tonic-gate continue; 2687c478bd9Sstevel@tonic-gate } else { 2697c478bd9Sstevel@tonic-gate if (!p->value) 2707c478bd9Sstevel@tonic-gate continue; 2717c478bd9Sstevel@tonic-gate if (value && (strcmp(p->value, value))) 2727c478bd9Sstevel@tonic-gate continue; 2737c478bd9Sstevel@tonic-gate } 274*505d05c7Sgtb if (p->deleted) 275*505d05c7Sgtb continue; 2767c478bd9Sstevel@tonic-gate /* A match! */ 2777c478bd9Sstevel@tonic-gate if (node) 2787c478bd9Sstevel@tonic-gate *node = p; 2797c478bd9Sstevel@tonic-gate break; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate if (p == 0) { 2827c478bd9Sstevel@tonic-gate *state = 0; 2837c478bd9Sstevel@tonic-gate return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * OK, we've found one match; now let's try to find another 2877c478bd9Sstevel@tonic-gate * one. This way, if we return a non-zero state pointer, 2887c478bd9Sstevel@tonic-gate * there's guaranteed to be another match that's returned. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate for (p = p->next; p; p = p->next) { 2917c478bd9Sstevel@tonic-gate if (name && (strcmp(p->name, name))) 2927c478bd9Sstevel@tonic-gate continue; 2937c478bd9Sstevel@tonic-gate if (section_flag) { 2947c478bd9Sstevel@tonic-gate if (p->value) 2957c478bd9Sstevel@tonic-gate continue; 2967c478bd9Sstevel@tonic-gate } else { 2977c478bd9Sstevel@tonic-gate if (!p->value) 2987c478bd9Sstevel@tonic-gate continue; 2997c478bd9Sstevel@tonic-gate if (value && (strcmp(p->value, value))) 3007c478bd9Sstevel@tonic-gate continue; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate /* A match! */ 3037c478bd9Sstevel@tonic-gate break; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate *state = p; 3067c478bd9Sstevel@tonic-gate return 0; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Iterate through the section, returning the relations which match 3127c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 3137c478bd9Sstevel@tonic-gate * relations in the section. The first time this routine is called, 3147c478bd9Sstevel@tonic-gate * the state pointer must be null. When this profile_find_node_relation() 3157c478bd9Sstevel@tonic-gate * returns, if the state pointer is non-NULL, then this routine should 3167c478bd9Sstevel@tonic-gate * be called again. 3177c478bd9Sstevel@tonic-gate * 3187c478bd9Sstevel@tonic-gate * The returned character string in value points to the stored 3197c478bd9Sstevel@tonic-gate * character string in the parse string. Before this string value is 3207c478bd9Sstevel@tonic-gate * returned to a calling application (profile_find_node_relation is not an 3217c478bd9Sstevel@tonic-gate * exported interface), it should be strdup()'ed. 3227c478bd9Sstevel@tonic-gate */ 323*505d05c7Sgtb errcode_t profile_find_node_relation(struct profile_node *section, 324*505d05c7Sgtb const char *name, void **state, 325*505d05c7Sgtb char **ret_name, char **value) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate struct profile_node *p; 3287c478bd9Sstevel@tonic-gate errcode_t retval; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate retval = profile_find_node(section, name, 0, 0, state, &p); 3317c478bd9Sstevel@tonic-gate if (retval) 3327c478bd9Sstevel@tonic-gate return retval; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (p) { 3357c478bd9Sstevel@tonic-gate if (value) 3367c478bd9Sstevel@tonic-gate *value = p->value; 3377c478bd9Sstevel@tonic-gate if (ret_name) 3387c478bd9Sstevel@tonic-gate *ret_name = p->name; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate return 0; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * Iterate through the section, returning the subsections which match 3457c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 3467c478bd9Sstevel@tonic-gate * subsections in the section. The first time this routine is called, 3477c478bd9Sstevel@tonic-gate * the state pointer must be null. When this profile_find_node_subsection() 3487c478bd9Sstevel@tonic-gate * returns, if the state pointer is non-NULL, then this routine should 3497c478bd9Sstevel@tonic-gate * be called again. 3507c478bd9Sstevel@tonic-gate * 3517c478bd9Sstevel@tonic-gate * This is (plus accessor functions for the name and value given a 3527c478bd9Sstevel@tonic-gate * profile node) makes this function mostly syntactic sugar for 353*505d05c7Sgtb * profile_find_node. 3547c478bd9Sstevel@tonic-gate */ 355*505d05c7Sgtb errcode_t profile_find_node_subsection(struct profile_node *section, 356*505d05c7Sgtb const char *name, void **state, 357*505d05c7Sgtb char **ret_name, 358*505d05c7Sgtb struct profile_node **subsection) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate struct profile_node *p; 3617c478bd9Sstevel@tonic-gate errcode_t retval; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (section == (struct profile_node *)NULL) 3647c478bd9Sstevel@tonic-gate return (PROF_NO_PROFILE); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate retval = profile_find_node(section, name, 0, 1, state, &p); 3677c478bd9Sstevel@tonic-gate if (retval) 3687c478bd9Sstevel@tonic-gate return retval; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (p) { 3717c478bd9Sstevel@tonic-gate if (subsection) 3727c478bd9Sstevel@tonic-gate *subsection = p; 3737c478bd9Sstevel@tonic-gate if (ret_name) 3747c478bd9Sstevel@tonic-gate *ret_name = p->name; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate return 0; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * This function returns the parent of a particular node. 3817c478bd9Sstevel@tonic-gate */ 382*505d05c7Sgtb errcode_t profile_get_node_parent(struct profile_node *section, 383*505d05c7Sgtb struct profile_node **parent) 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate *parent = section->parent; 3867c478bd9Sstevel@tonic-gate return 0; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate * This is a general-purpose iterator for returning all nodes that 391*505d05c7Sgtb * match the specified name array. 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate struct profile_iterator { 3947c478bd9Sstevel@tonic-gate prf_magic_t magic; 3957c478bd9Sstevel@tonic-gate profile_t profile; 3967c478bd9Sstevel@tonic-gate int flags; 397*505d05c7Sgtb const char *const *names; 3987c478bd9Sstevel@tonic-gate const char *name; 3997c478bd9Sstevel@tonic-gate prf_file_t file; 4007c478bd9Sstevel@tonic-gate int file_serial; 4017c478bd9Sstevel@tonic-gate int done_idx; 4027c478bd9Sstevel@tonic-gate struct profile_node *node; 4037c478bd9Sstevel@tonic-gate int num; 4047c478bd9Sstevel@tonic-gate }; 4057c478bd9Sstevel@tonic-gate 406*505d05c7Sgtb errcode_t profile_node_iterator_create(profile_t profile, 407*505d05c7Sgtb const char *const *names, int flags, 408*505d05c7Sgtb void **ret_iter) 4097c478bd9Sstevel@tonic-gate { 4107c478bd9Sstevel@tonic-gate struct profile_iterator *iter; 4117c478bd9Sstevel@tonic-gate int done_idx = 0; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if (profile == 0) 4147c478bd9Sstevel@tonic-gate return PROF_NO_PROFILE; 4157c478bd9Sstevel@tonic-gate if (profile->magic != PROF_MAGIC_PROFILE) 4167c478bd9Sstevel@tonic-gate return PROF_MAGIC_PROFILE; 4177c478bd9Sstevel@tonic-gate if (!names) 4187c478bd9Sstevel@tonic-gate return PROF_BAD_NAMESET; 4197c478bd9Sstevel@tonic-gate if (!(flags & PROFILE_ITER_LIST_SECTION)) { 4207c478bd9Sstevel@tonic-gate if (!names[0]) 4217c478bd9Sstevel@tonic-gate return PROF_BAD_NAMESET; 4227c478bd9Sstevel@tonic-gate done_idx = 1; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if ((iter = (struct profile_iterator *) 4267c478bd9Sstevel@tonic-gate malloc(sizeof(struct profile_iterator))) == NULL) 4277c478bd9Sstevel@tonic-gate return ENOMEM; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate iter->magic = PROF_MAGIC_ITERATOR; 4307c478bd9Sstevel@tonic-gate iter->profile = profile; 4317c478bd9Sstevel@tonic-gate iter->names = names; 4327c478bd9Sstevel@tonic-gate iter->flags = flags; 4337c478bd9Sstevel@tonic-gate iter->file = profile->first_file; 4347c478bd9Sstevel@tonic-gate iter->done_idx = done_idx; 4357c478bd9Sstevel@tonic-gate iter->node = 0; 4367c478bd9Sstevel@tonic-gate iter->num = 0; 4377c478bd9Sstevel@tonic-gate *ret_iter = iter; 4387c478bd9Sstevel@tonic-gate return 0; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 441*505d05c7Sgtb void profile_node_iterator_free(void **iter_p) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate struct profile_iterator *iter; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (!iter_p) 4467c478bd9Sstevel@tonic-gate return; 4477c478bd9Sstevel@tonic-gate iter = *iter_p; 4487c478bd9Sstevel@tonic-gate if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 4497c478bd9Sstevel@tonic-gate return; 4507c478bd9Sstevel@tonic-gate free(iter); 4517c478bd9Sstevel@tonic-gate *iter_p = 0; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Note: the returned character strings in ret_name and ret_value 4567c478bd9Sstevel@tonic-gate * points to the stored character string in the parse string. Before 4577c478bd9Sstevel@tonic-gate * this string value is returned to a calling application 4587c478bd9Sstevel@tonic-gate * (profile_node_iterator is not an exported interface), it should be 4597c478bd9Sstevel@tonic-gate * strdup()'ed. 4607c478bd9Sstevel@tonic-gate */ 461*505d05c7Sgtb errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, 462*505d05c7Sgtb char **ret_name, char **ret_value) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate struct profile_iterator *iter = *iter_p; 4657c478bd9Sstevel@tonic-gate struct profile_node *section, *p; 466*505d05c7Sgtb const char *const *cpp; 4677c478bd9Sstevel@tonic-gate errcode_t retval; 4687c478bd9Sstevel@tonic-gate int skip_num = 0; 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 4717c478bd9Sstevel@tonic-gate return PROF_MAGIC_ITERATOR; 472*505d05c7Sgtb if (iter->file && iter->file->magic != PROF_MAGIC_FILE) 473*505d05c7Sgtb return PROF_MAGIC_FILE; 474*505d05c7Sgtb if (iter->file && iter->file->data->magic != PROF_MAGIC_FILE_DATA) 475*505d05c7Sgtb return PROF_MAGIC_FILE_DATA; 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * If the file has changed, then the node pointer is invalid, 4787c478bd9Sstevel@tonic-gate * so we'll have search the file again looking for it. 4797c478bd9Sstevel@tonic-gate */ 480*505d05c7Sgtb if (iter->file) { 481*505d05c7Sgtb retval = k5_mutex_lock(&iter->file->data->lock); 482*505d05c7Sgtb if (retval) 483*505d05c7Sgtb return retval; 484*505d05c7Sgtb } 485*505d05c7Sgtb if (iter->node && (iter->file->data->upd_serial != iter->file_serial)) { 4867c478bd9Sstevel@tonic-gate iter->flags &= ~PROFILE_ITER_FINAL_SEEN; 4877c478bd9Sstevel@tonic-gate skip_num = iter->num; 4887c478bd9Sstevel@tonic-gate iter->node = 0; 4897c478bd9Sstevel@tonic-gate } 490*505d05c7Sgtb if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { 491*505d05c7Sgtb if (iter->file) 492*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 493*505d05c7Sgtb return PROF_MAGIC_NODE; 494*505d05c7Sgtb } 4957c478bd9Sstevel@tonic-gate get_new_file: 4967c478bd9Sstevel@tonic-gate if (iter->node == 0) { 4977c478bd9Sstevel@tonic-gate if (iter->file == 0 || 4987c478bd9Sstevel@tonic-gate (iter->flags & PROFILE_ITER_FINAL_SEEN)) { 499*505d05c7Sgtb if (iter->file) 500*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 5017c478bd9Sstevel@tonic-gate profile_node_iterator_free(iter_p); 5027c478bd9Sstevel@tonic-gate if (ret_node) 5037c478bd9Sstevel@tonic-gate *ret_node = 0; 5047c478bd9Sstevel@tonic-gate if (ret_name) 5057c478bd9Sstevel@tonic-gate *ret_name = 0; 5067c478bd9Sstevel@tonic-gate if (ret_value) 5077c478bd9Sstevel@tonic-gate *ret_value =0; 5087c478bd9Sstevel@tonic-gate return 0; 5097c478bd9Sstevel@tonic-gate } 510*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 5117c478bd9Sstevel@tonic-gate if ((retval = profile_update_file(iter->file))) { 512*505d05c7Sgtb if (retval == ENOENT || retval == EACCES) { 513*505d05c7Sgtb /* XXX memory leak? */ 514*505d05c7Sgtb iter->file = iter->file->next; 515*505d05c7Sgtb if (iter->file) { 516*505d05c7Sgtb retval = k5_mutex_lock(&iter->file->data->lock); 517*505d05c7Sgtb if (retval) { 518*505d05c7Sgtb profile_node_iterator_free(iter_p); 519*505d05c7Sgtb return retval; 520*505d05c7Sgtb } 521*505d05c7Sgtb } 522*505d05c7Sgtb skip_num = 0; 523*505d05c7Sgtb retval = 0; 524*505d05c7Sgtb goto get_new_file; 525*505d05c7Sgtb } else { 5267c478bd9Sstevel@tonic-gate profile_node_iterator_free(iter_p); 5277c478bd9Sstevel@tonic-gate return retval; 528*505d05c7Sgtb } 529*505d05c7Sgtb } 530*505d05c7Sgtb retval = k5_mutex_lock(&iter->file->data->lock); 531*505d05c7Sgtb if (retval) { 532*505d05c7Sgtb profile_node_iterator_free(iter_p); 533*505d05c7Sgtb return retval; 5347c478bd9Sstevel@tonic-gate } 535*505d05c7Sgtb iter->file_serial = iter->file->data->upd_serial; 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * Find the section to list if we are a LIST_SECTION, 5387c478bd9Sstevel@tonic-gate * or find the containing section if not. 5397c478bd9Sstevel@tonic-gate */ 540*505d05c7Sgtb section = iter->file->data->root; 5417c478bd9Sstevel@tonic-gate for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { 542*505d05c7Sgtb for (p=section->first_child; p; p = p->next) { 5437c478bd9Sstevel@tonic-gate if (!strcmp(p->name, *cpp) && !p->value) 5447c478bd9Sstevel@tonic-gate break; 545*505d05c7Sgtb } 5467c478bd9Sstevel@tonic-gate if (!p) { 5477c478bd9Sstevel@tonic-gate section = 0; 5487c478bd9Sstevel@tonic-gate break; 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate section = p; 5517c478bd9Sstevel@tonic-gate if (p->final) 5527c478bd9Sstevel@tonic-gate iter->flags |= PROFILE_ITER_FINAL_SEEN; 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate if (!section) { 555*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 5567c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 557*505d05c7Sgtb if (iter->file) { 558*505d05c7Sgtb retval = k5_mutex_lock(&iter->file->data->lock); 559*505d05c7Sgtb if (retval) { 560*505d05c7Sgtb profile_node_iterator_free(iter_p); 561*505d05c7Sgtb return retval; 562*505d05c7Sgtb } 563*505d05c7Sgtb } 5647c478bd9Sstevel@tonic-gate skip_num = 0; 5657c478bd9Sstevel@tonic-gate goto get_new_file; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate iter->name = *cpp; 5687c478bd9Sstevel@tonic-gate iter->node = section->first_child; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * OK, now we know iter->node is set up correctly. Let's do 5727c478bd9Sstevel@tonic-gate * the search. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate for (p = iter->node; p; p = p->next) { 5757c478bd9Sstevel@tonic-gate if (iter->name && strcmp(p->name, iter->name)) 5767c478bd9Sstevel@tonic-gate continue; 5777c478bd9Sstevel@tonic-gate if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && 5787c478bd9Sstevel@tonic-gate p->value) 5797c478bd9Sstevel@tonic-gate continue; 5807c478bd9Sstevel@tonic-gate if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && 5817c478bd9Sstevel@tonic-gate !p->value) 5827c478bd9Sstevel@tonic-gate continue; 5837c478bd9Sstevel@tonic-gate if (skip_num > 0) { 5847c478bd9Sstevel@tonic-gate skip_num--; 5857c478bd9Sstevel@tonic-gate continue; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate break; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate iter->num++; 5907c478bd9Sstevel@tonic-gate if (!p) { 591*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 5927c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 593*505d05c7Sgtb if (iter->file) { 594*505d05c7Sgtb retval = k5_mutex_lock(&iter->file->data->lock); 595*505d05c7Sgtb if (retval) { 596*505d05c7Sgtb profile_node_iterator_free(iter_p); 597*505d05c7Sgtb return retval; 598*505d05c7Sgtb } 599*505d05c7Sgtb } 6007c478bd9Sstevel@tonic-gate iter->node = 0; 6017c478bd9Sstevel@tonic-gate skip_num = 0; 6027c478bd9Sstevel@tonic-gate goto get_new_file; 6037c478bd9Sstevel@tonic-gate } 604*505d05c7Sgtb k5_mutex_unlock(&iter->file->data->lock); 6057c478bd9Sstevel@tonic-gate if ((iter->node = p->next) == NULL) 6067c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 6077c478bd9Sstevel@tonic-gate if (ret_node) 6087c478bd9Sstevel@tonic-gate *ret_node = p; 6097c478bd9Sstevel@tonic-gate if (ret_name) 6107c478bd9Sstevel@tonic-gate *ret_name = p->name; 6117c478bd9Sstevel@tonic-gate if (ret_value) 6127c478bd9Sstevel@tonic-gate *ret_value = p->value; 6137c478bd9Sstevel@tonic-gate return 0; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 616*505d05c7Sgtb /* 6177c478bd9Sstevel@tonic-gate * Remove a particular node. 618*505d05c7Sgtb * 6197c478bd9Sstevel@tonic-gate * TYT, 2/25/99 6207c478bd9Sstevel@tonic-gate */ 621*505d05c7Sgtb errcode_t profile_remove_node(struct profile_node *node) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (node->parent == 0) 6267c478bd9Sstevel@tonic-gate return PROF_EINVAL; /* Can't remove the root! */ 6277c478bd9Sstevel@tonic-gate 628*505d05c7Sgtb node->deleted = 1; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate return 0; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Set the value of a specific node containing a relation. 6357c478bd9Sstevel@tonic-gate * 6367c478bd9Sstevel@tonic-gate * TYT, 2/25/99 6377c478bd9Sstevel@tonic-gate */ 638*505d05c7Sgtb errcode_t profile_set_relation_value(struct profile_node *node, 639*505d05c7Sgtb const char *new_value) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate char *cp; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (!node->value) 6467c478bd9Sstevel@tonic-gate return PROF_SET_SECTION_VALUE; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate cp = (char *) malloc(strlen(new_value)+1); 6497c478bd9Sstevel@tonic-gate if (!cp) 6507c478bd9Sstevel@tonic-gate return ENOMEM; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate strcpy(cp, new_value); 6537c478bd9Sstevel@tonic-gate free(node->value); 6547c478bd9Sstevel@tonic-gate node->value = cp; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate return 0; 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * Rename a specific node 6617c478bd9Sstevel@tonic-gate * 6627c478bd9Sstevel@tonic-gate * TYT 2/25/99 6637c478bd9Sstevel@tonic-gate */ 664*505d05c7Sgtb errcode_t profile_rename_node(struct profile_node *node, const char *new_name) 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate char *new_string; 6677c478bd9Sstevel@tonic-gate struct profile_node *p, *last; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate if (strcmp(new_name, node->name) == 0) 6727c478bd9Sstevel@tonic-gate return 0; /* It's the same name, return */ 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * Make sure we can allocate memory for the new name, first! 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate new_string = (char *) malloc(strlen(new_name)+1); 6787c478bd9Sstevel@tonic-gate if (!new_string) 6797c478bd9Sstevel@tonic-gate return ENOMEM; 6807c478bd9Sstevel@tonic-gate strcpy(new_string, new_name); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * Find the place to where the new node should go. We look 6847c478bd9Sstevel@tonic-gate * for the place *after* the last match of the node name, 6857c478bd9Sstevel@tonic-gate * since order matters. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) { 6887c478bd9Sstevel@tonic-gate if (strcmp(p->name, new_name) > 0) 6897c478bd9Sstevel@tonic-gate break; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * If we need to move the node, do it now. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate if ((p != node) && (last != node)) { 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * OK, let's detach the node 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if (node->prev) 7007c478bd9Sstevel@tonic-gate node->prev->next = node->next; 7017c478bd9Sstevel@tonic-gate else 7027c478bd9Sstevel@tonic-gate node->parent->first_child = node->next; 7037c478bd9Sstevel@tonic-gate if (node->next) 7047c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * Now let's reattach it in the right place. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate if (p) 7107c478bd9Sstevel@tonic-gate p->prev = node; 7117c478bd9Sstevel@tonic-gate if (last) 7127c478bd9Sstevel@tonic-gate last->next = node; 7137c478bd9Sstevel@tonic-gate else 7147c478bd9Sstevel@tonic-gate node->parent->first_child = node; 7157c478bd9Sstevel@tonic-gate node->next = p; 7167c478bd9Sstevel@tonic-gate node->prev = last; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate free(node->name); 7207c478bd9Sstevel@tonic-gate node->name = new_string; 7217c478bd9Sstevel@tonic-gate return 0; 7227c478bd9Sstevel@tonic-gate } 723