1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * prof_tree.c --- these routines maintain the parse tree of the 10*7c478bd9Sstevel@tonic-gate * config file. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate * All of the details of how the tree is stored is abstracted away in 13*7c478bd9Sstevel@tonic-gate * this file; all of the other profile routines build, access, and 14*7c478bd9Sstevel@tonic-gate * modify the tree via the accessor functions found in this file. 15*7c478bd9Sstevel@tonic-gate * 16*7c478bd9Sstevel@tonic-gate * Each node may represent either a relation or a section header. 17*7c478bd9Sstevel@tonic-gate * 18*7c478bd9Sstevel@tonic-gate * A section header must have its value field set to 0, and may a one 19*7c478bd9Sstevel@tonic-gate * or more child nodes, pointed to by first_child. 20*7c478bd9Sstevel@tonic-gate * 21*7c478bd9Sstevel@tonic-gate * A relation has as its value a pointer to allocated memory 22*7c478bd9Sstevel@tonic-gate * containing a string. Its first_child pointer must be null. 23*7c478bd9Sstevel@tonic-gate * 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #include <stdio.h> 27*7c478bd9Sstevel@tonic-gate #include <string.h> 28*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H 29*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 30*7c478bd9Sstevel@tonic-gate #endif 31*7c478bd9Sstevel@tonic-gate #include <errno.h> 32*7c478bd9Sstevel@tonic-gate #include <ctype.h> 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include "prof_int.h" 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate struct profile_node { 37*7c478bd9Sstevel@tonic-gate errcode_t magic; 38*7c478bd9Sstevel@tonic-gate char *name; 39*7c478bd9Sstevel@tonic-gate char *value; 40*7c478bd9Sstevel@tonic-gate int group_level; 41*7c478bd9Sstevel@tonic-gate int final:1; /* Indicate don't search next file */ 42*7c478bd9Sstevel@tonic-gate struct profile_node *first_child; 43*7c478bd9Sstevel@tonic-gate struct profile_node *parent; 44*7c478bd9Sstevel@tonic-gate struct profile_node *next, *prev; 45*7c478bd9Sstevel@tonic-gate }; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #define CHECK_MAGIC(node) \ 48*7c478bd9Sstevel@tonic-gate if ((node)->magic != PROF_MAGIC_NODE) \ 49*7c478bd9Sstevel@tonic-gate return PROF_MAGIC_NODE; 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * Free a node, and any children 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate void profile_free_node(node) 55*7c478bd9Sstevel@tonic-gate struct profile_node *node; 56*7c478bd9Sstevel@tonic-gate { 57*7c478bd9Sstevel@tonic-gate struct profile_node *child, *next; 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate if (node->magic != PROF_MAGIC_NODE) 60*7c478bd9Sstevel@tonic-gate return; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate if (node->name) 63*7c478bd9Sstevel@tonic-gate free(node->name); 64*7c478bd9Sstevel@tonic-gate if (node->value) 65*7c478bd9Sstevel@tonic-gate free(node->value); 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate for (child=node->first_child; child; child = next) { 68*7c478bd9Sstevel@tonic-gate next = child->next; 69*7c478bd9Sstevel@tonic-gate profile_free_node(child); 70*7c478bd9Sstevel@tonic-gate } 71*7c478bd9Sstevel@tonic-gate node->magic = 0; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate free(node); 74*7c478bd9Sstevel@tonic-gate } 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* 77*7c478bd9Sstevel@tonic-gate * Create a node 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate errcode_t profile_create_node(name, value, ret_node) 80*7c478bd9Sstevel@tonic-gate const char *name, *value; 81*7c478bd9Sstevel@tonic-gate struct profile_node **ret_node; 82*7c478bd9Sstevel@tonic-gate { 83*7c478bd9Sstevel@tonic-gate struct profile_node *new; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate new = (struct profile_node *)malloc(sizeof(struct profile_node)); 86*7c478bd9Sstevel@tonic-gate if (!new) 87*7c478bd9Sstevel@tonic-gate return ENOMEM; 88*7c478bd9Sstevel@tonic-gate memset(new, 0, sizeof(struct profile_node)); 89*7c478bd9Sstevel@tonic-gate new->name = (char *) malloc(strlen(name)+1); 90*7c478bd9Sstevel@tonic-gate if (new->name == 0) { 91*7c478bd9Sstevel@tonic-gate profile_free_node(new); 92*7c478bd9Sstevel@tonic-gate return ENOMEM; 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate strcpy(new->name, name); 95*7c478bd9Sstevel@tonic-gate if (value) { 96*7c478bd9Sstevel@tonic-gate new->value = (char *) malloc(strlen(value)+1); 97*7c478bd9Sstevel@tonic-gate if (new->value == 0) { 98*7c478bd9Sstevel@tonic-gate profile_free_node(new); 99*7c478bd9Sstevel@tonic-gate return ENOMEM; 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate strcpy(new->value, value); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate new->magic = PROF_MAGIC_NODE; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate *ret_node = new; 106*7c478bd9Sstevel@tonic-gate return 0; 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * This function verifies that all of the representation invarients of 111*7c478bd9Sstevel@tonic-gate * the profile are true. If not, we have a programming bug somewhere, 112*7c478bd9Sstevel@tonic-gate * probably in this file. 113*7c478bd9Sstevel@tonic-gate */ 114*7c478bd9Sstevel@tonic-gate errcode_t profile_verify_node(node) 115*7c478bd9Sstevel@tonic-gate struct profile_node *node; 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate struct profile_node *p, *last; 118*7c478bd9Sstevel@tonic-gate errcode_t retval; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate if (node->value && node->first_child) 123*7c478bd9Sstevel@tonic-gate return PROF_SECTION_WITH_VALUE; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate last = 0; 126*7c478bd9Sstevel@tonic-gate for (p = node->first_child; p; last = p, p = p->next) { 127*7c478bd9Sstevel@tonic-gate if (p->prev != last) 128*7c478bd9Sstevel@tonic-gate return PROF_BAD_LINK_LIST; 129*7c478bd9Sstevel@tonic-gate if (last && (last->next != p)) 130*7c478bd9Sstevel@tonic-gate return PROF_BAD_LINK_LIST; 131*7c478bd9Sstevel@tonic-gate if (node->group_level+1 != p->group_level) 132*7c478bd9Sstevel@tonic-gate return PROF_BAD_GROUP_LVL; 133*7c478bd9Sstevel@tonic-gate if (p->parent != node) 134*7c478bd9Sstevel@tonic-gate return PROF_BAD_PARENT_PTR; 135*7c478bd9Sstevel@tonic-gate retval = profile_verify_node(p); 136*7c478bd9Sstevel@tonic-gate if (retval) 137*7c478bd9Sstevel@tonic-gate return retval; 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate return 0; 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate * Add a node to a particular section 144*7c478bd9Sstevel@tonic-gate */ 145*7c478bd9Sstevel@tonic-gate errcode_t profile_add_node(section, name, value, ret_node) 146*7c478bd9Sstevel@tonic-gate struct profile_node *section; 147*7c478bd9Sstevel@tonic-gate const char *name, *value; 148*7c478bd9Sstevel@tonic-gate struct profile_node **ret_node; 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate errcode_t retval; 151*7c478bd9Sstevel@tonic-gate struct profile_node *p, *last, *new; 152*7c478bd9Sstevel@tonic-gate int cmp = -1; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(section); 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate if (section->value) 157*7c478bd9Sstevel@tonic-gate return PROF_ADD_NOT_SECTION; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* 160*7c478bd9Sstevel@tonic-gate * Find the place to insert the new node. We look for the 161*7c478bd9Sstevel@tonic-gate * place *after* the last match of the node name, since 162*7c478bd9Sstevel@tonic-gate * order matters. 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate for (p=section->first_child, last = 0; p; last = p, p = p->next) { 165*7c478bd9Sstevel@tonic-gate cmp = strcmp(p->name, name); 166*7c478bd9Sstevel@tonic-gate if (cmp > 0) 167*7c478bd9Sstevel@tonic-gate break; 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate retval = profile_create_node(name, value, &new); 170*7c478bd9Sstevel@tonic-gate if (retval) 171*7c478bd9Sstevel@tonic-gate return retval; 172*7c478bd9Sstevel@tonic-gate new->group_level = section->group_level+1; 173*7c478bd9Sstevel@tonic-gate new->parent = section; 174*7c478bd9Sstevel@tonic-gate new->prev = last; 175*7c478bd9Sstevel@tonic-gate new->next = p; 176*7c478bd9Sstevel@tonic-gate if (p) 177*7c478bd9Sstevel@tonic-gate p->prev = new; 178*7c478bd9Sstevel@tonic-gate if (last) 179*7c478bd9Sstevel@tonic-gate last->next = new; 180*7c478bd9Sstevel@tonic-gate else 181*7c478bd9Sstevel@tonic-gate section->first_child = new; 182*7c478bd9Sstevel@tonic-gate if (ret_node) 183*7c478bd9Sstevel@tonic-gate *ret_node = new; 184*7c478bd9Sstevel@tonic-gate return 0; 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Set the final flag on a particular node. 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate errcode_t profile_make_node_final(node) 191*7c478bd9Sstevel@tonic-gate struct profile_node *node; 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate node->final = 1; 196*7c478bd9Sstevel@tonic-gate return 0; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate /* 200*7c478bd9Sstevel@tonic-gate * Check the final flag on a node 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate int profile_is_node_final(node) 203*7c478bd9Sstevel@tonic-gate struct profile_node *node; 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate return (node->final != 0); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* 209*7c478bd9Sstevel@tonic-gate * Return the name of a node. (Note: this is for internal functions 210*7c478bd9Sstevel@tonic-gate * only; if the name needs to be returned from an exported function, 211*7c478bd9Sstevel@tonic-gate * strdup it first!) 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate const char *profile_get_node_name(node) 214*7c478bd9Sstevel@tonic-gate struct profile_node *node; 215*7c478bd9Sstevel@tonic-gate { 216*7c478bd9Sstevel@tonic-gate return node->name; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * Return the value of a node. (Note: this is for internal functions 221*7c478bd9Sstevel@tonic-gate * only; if the name needs to be returned from an exported function, 222*7c478bd9Sstevel@tonic-gate * strdup it first!) 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate const char *profile_get_node_value(node) 225*7c478bd9Sstevel@tonic-gate struct profile_node *node; 226*7c478bd9Sstevel@tonic-gate { 227*7c478bd9Sstevel@tonic-gate return node->value; 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Iterate through the section, returning the nodes which match 232*7c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 233*7c478bd9Sstevel@tonic-gate * nodes in the section. If section_flag is non-zero, only return the 234*7c478bd9Sstevel@tonic-gate * section which matches the name; don't return relations. If value 235*7c478bd9Sstevel@tonic-gate * is non-NULL, then only return relations which match the requested 236*7c478bd9Sstevel@tonic-gate * value. (The value argument is ignored if section_flag is non-zero.) 237*7c478bd9Sstevel@tonic-gate * 238*7c478bd9Sstevel@tonic-gate * The first time this routine is called, the state pointer must be 239*7c478bd9Sstevel@tonic-gate * null. When this profile_find_node_relation() returns, if the state 240*7c478bd9Sstevel@tonic-gate * pointer is non-NULL, then this routine should be called again. 241*7c478bd9Sstevel@tonic-gate * (This won't happen if section_flag is non-zero, obviously.) 242*7c478bd9Sstevel@tonic-gate * 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node(section, name, value, section_flag, state, node) 245*7c478bd9Sstevel@tonic-gate struct profile_node *section; 246*7c478bd9Sstevel@tonic-gate const char *name; 247*7c478bd9Sstevel@tonic-gate const char *value; 248*7c478bd9Sstevel@tonic-gate int section_flag; 249*7c478bd9Sstevel@tonic-gate void **state; 250*7c478bd9Sstevel@tonic-gate struct profile_node **node; 251*7c478bd9Sstevel@tonic-gate { 252*7c478bd9Sstevel@tonic-gate struct profile_node *p; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(section); 255*7c478bd9Sstevel@tonic-gate p = *state; 256*7c478bd9Sstevel@tonic-gate if (p) { 257*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(p); 258*7c478bd9Sstevel@tonic-gate } else 259*7c478bd9Sstevel@tonic-gate p = section->first_child; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate for (; p; p = p->next) { 262*7c478bd9Sstevel@tonic-gate if (name && (strcmp(p->name, name))) 263*7c478bd9Sstevel@tonic-gate continue; 264*7c478bd9Sstevel@tonic-gate if (section_flag) { 265*7c478bd9Sstevel@tonic-gate if (p->value) 266*7c478bd9Sstevel@tonic-gate continue; 267*7c478bd9Sstevel@tonic-gate } else { 268*7c478bd9Sstevel@tonic-gate if (!p->value) 269*7c478bd9Sstevel@tonic-gate continue; 270*7c478bd9Sstevel@tonic-gate if (value && (strcmp(p->value, value))) 271*7c478bd9Sstevel@tonic-gate continue; 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate /* A match! */ 274*7c478bd9Sstevel@tonic-gate if (node) 275*7c478bd9Sstevel@tonic-gate *node = p; 276*7c478bd9Sstevel@tonic-gate break; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate if (p == 0) { 279*7c478bd9Sstevel@tonic-gate *state = 0; 280*7c478bd9Sstevel@tonic-gate return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate * OK, we've found one match; now let's try to find another 284*7c478bd9Sstevel@tonic-gate * one. This way, if we return a non-zero state pointer, 285*7c478bd9Sstevel@tonic-gate * there's guaranteed to be another match that's returned. 286*7c478bd9Sstevel@tonic-gate */ 287*7c478bd9Sstevel@tonic-gate for (p = p->next; p; p = p->next) { 288*7c478bd9Sstevel@tonic-gate if (name && (strcmp(p->name, name))) 289*7c478bd9Sstevel@tonic-gate continue; 290*7c478bd9Sstevel@tonic-gate if (section_flag) { 291*7c478bd9Sstevel@tonic-gate if (p->value) 292*7c478bd9Sstevel@tonic-gate continue; 293*7c478bd9Sstevel@tonic-gate } else { 294*7c478bd9Sstevel@tonic-gate if (!p->value) 295*7c478bd9Sstevel@tonic-gate continue; 296*7c478bd9Sstevel@tonic-gate if (value && (strcmp(p->value, value))) 297*7c478bd9Sstevel@tonic-gate continue; 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate /* A match! */ 300*7c478bd9Sstevel@tonic-gate break; 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate *state = p; 303*7c478bd9Sstevel@tonic-gate return 0; 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * Iterate through the section, returning the relations which match 309*7c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 310*7c478bd9Sstevel@tonic-gate * relations in the section. The first time this routine is called, 311*7c478bd9Sstevel@tonic-gate * the state pointer must be null. When this profile_find_node_relation() 312*7c478bd9Sstevel@tonic-gate * returns, if the state pointer is non-NULL, then this routine should 313*7c478bd9Sstevel@tonic-gate * be called again. 314*7c478bd9Sstevel@tonic-gate * 315*7c478bd9Sstevel@tonic-gate * The returned character string in value points to the stored 316*7c478bd9Sstevel@tonic-gate * character string in the parse string. Before this string value is 317*7c478bd9Sstevel@tonic-gate * returned to a calling application (profile_find_node_relation is not an 318*7c478bd9Sstevel@tonic-gate * exported interface), it should be strdup()'ed. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node_relation(section, name, state, ret_name, value) 321*7c478bd9Sstevel@tonic-gate struct profile_node *section; 322*7c478bd9Sstevel@tonic-gate const char *name; 323*7c478bd9Sstevel@tonic-gate void **state; 324*7c478bd9Sstevel@tonic-gate char **ret_name, **value; 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate struct profile_node *p; 327*7c478bd9Sstevel@tonic-gate errcode_t retval; 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate retval = profile_find_node(section, name, 0, 0, state, &p); 330*7c478bd9Sstevel@tonic-gate if (retval) 331*7c478bd9Sstevel@tonic-gate return retval; 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate if (p) { 334*7c478bd9Sstevel@tonic-gate if (value) 335*7c478bd9Sstevel@tonic-gate *value = p->value; 336*7c478bd9Sstevel@tonic-gate if (ret_name) 337*7c478bd9Sstevel@tonic-gate *ret_name = p->name; 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate return 0; 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * Iterate through the section, returning the subsections which match 344*7c478bd9Sstevel@tonic-gate * the given name. If name is NULL, then interate through all the 345*7c478bd9Sstevel@tonic-gate * subsections in the section. The first time this routine is called, 346*7c478bd9Sstevel@tonic-gate * the state pointer must be null. When this profile_find_node_subsection() 347*7c478bd9Sstevel@tonic-gate * returns, if the state pointer is non-NULL, then this routine should 348*7c478bd9Sstevel@tonic-gate * be called again. 349*7c478bd9Sstevel@tonic-gate * 350*7c478bd9Sstevel@tonic-gate * This is (plus accessor functions for the name and value given a 351*7c478bd9Sstevel@tonic-gate * profile node) makes this function mostly syntactic sugar for 352*7c478bd9Sstevel@tonic-gate * profile_find_node. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node_subsection(section, name, state, ret_name, 355*7c478bd9Sstevel@tonic-gate subsection) 356*7c478bd9Sstevel@tonic-gate struct profile_node *section; 357*7c478bd9Sstevel@tonic-gate const char *name; 358*7c478bd9Sstevel@tonic-gate void **state; 359*7c478bd9Sstevel@tonic-gate char **ret_name; 360*7c478bd9Sstevel@tonic-gate struct profile_node **subsection; 361*7c478bd9Sstevel@tonic-gate { 362*7c478bd9Sstevel@tonic-gate struct profile_node *p; 363*7c478bd9Sstevel@tonic-gate errcode_t retval; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if (section == (struct profile_node *)NULL) 366*7c478bd9Sstevel@tonic-gate return (PROF_NO_PROFILE); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate retval = profile_find_node(section, name, 0, 1, state, &p); 369*7c478bd9Sstevel@tonic-gate if (retval) 370*7c478bd9Sstevel@tonic-gate return retval; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (p) { 373*7c478bd9Sstevel@tonic-gate if (subsection) 374*7c478bd9Sstevel@tonic-gate *subsection = p; 375*7c478bd9Sstevel@tonic-gate if (ret_name) 376*7c478bd9Sstevel@tonic-gate *ret_name = p->name; 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate return 0; 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * This function returns the parent of a particular node. 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate errcode_t profile_get_node_parent(section, parent) 385*7c478bd9Sstevel@tonic-gate struct profile_node *section, **parent; 386*7c478bd9Sstevel@tonic-gate { 387*7c478bd9Sstevel@tonic-gate *parent = section->parent; 388*7c478bd9Sstevel@tonic-gate return 0; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* 392*7c478bd9Sstevel@tonic-gate * This is a general-purpose iterator for returning all nodes that 393*7c478bd9Sstevel@tonic-gate * match the specified name array. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate struct profile_iterator { 396*7c478bd9Sstevel@tonic-gate prf_magic_t magic; 397*7c478bd9Sstevel@tonic-gate profile_t profile; 398*7c478bd9Sstevel@tonic-gate int flags; 399*7c478bd9Sstevel@tonic-gate const char **names; 400*7c478bd9Sstevel@tonic-gate const char *name; 401*7c478bd9Sstevel@tonic-gate prf_file_t file; 402*7c478bd9Sstevel@tonic-gate int file_serial; 403*7c478bd9Sstevel@tonic-gate int done_idx; 404*7c478bd9Sstevel@tonic-gate struct profile_node *node; 405*7c478bd9Sstevel@tonic-gate int num; 406*7c478bd9Sstevel@tonic-gate }; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate errcode_t profile_node_iterator_create(profile, names, flags, ret_iter) 409*7c478bd9Sstevel@tonic-gate profile_t profile; 410*7c478bd9Sstevel@tonic-gate const char **names; 411*7c478bd9Sstevel@tonic-gate int flags; 412*7c478bd9Sstevel@tonic-gate void **ret_iter; 413*7c478bd9Sstevel@tonic-gate { 414*7c478bd9Sstevel@tonic-gate struct profile_iterator *iter; 415*7c478bd9Sstevel@tonic-gate int done_idx = 0; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate if (profile == 0) 418*7c478bd9Sstevel@tonic-gate return PROF_NO_PROFILE; 419*7c478bd9Sstevel@tonic-gate if (profile->magic != PROF_MAGIC_PROFILE) 420*7c478bd9Sstevel@tonic-gate return PROF_MAGIC_PROFILE; 421*7c478bd9Sstevel@tonic-gate if (!names) 422*7c478bd9Sstevel@tonic-gate return PROF_BAD_NAMESET; 423*7c478bd9Sstevel@tonic-gate if (!(flags & PROFILE_ITER_LIST_SECTION)) { 424*7c478bd9Sstevel@tonic-gate if (!names[0]) 425*7c478bd9Sstevel@tonic-gate return PROF_BAD_NAMESET; 426*7c478bd9Sstevel@tonic-gate done_idx = 1; 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate if ((iter = (struct profile_iterator *) 430*7c478bd9Sstevel@tonic-gate malloc(sizeof(struct profile_iterator))) == NULL) 431*7c478bd9Sstevel@tonic-gate return ENOMEM; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate iter->magic = PROF_MAGIC_ITERATOR; 434*7c478bd9Sstevel@tonic-gate iter->profile = profile; 435*7c478bd9Sstevel@tonic-gate iter->names = names; 436*7c478bd9Sstevel@tonic-gate iter->flags = flags; 437*7c478bd9Sstevel@tonic-gate iter->file = profile->first_file; 438*7c478bd9Sstevel@tonic-gate iter->done_idx = done_idx; 439*7c478bd9Sstevel@tonic-gate iter->node = 0; 440*7c478bd9Sstevel@tonic-gate iter->num = 0; 441*7c478bd9Sstevel@tonic-gate *ret_iter = iter; 442*7c478bd9Sstevel@tonic-gate return 0; 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate void profile_node_iterator_free(iter_p) 446*7c478bd9Sstevel@tonic-gate void **iter_p; 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate struct profile_iterator *iter; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (!iter_p) 451*7c478bd9Sstevel@tonic-gate return; 452*7c478bd9Sstevel@tonic-gate iter = *iter_p; 453*7c478bd9Sstevel@tonic-gate if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 454*7c478bd9Sstevel@tonic-gate return; 455*7c478bd9Sstevel@tonic-gate free(iter); 456*7c478bd9Sstevel@tonic-gate *iter_p = 0; 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate /* 460*7c478bd9Sstevel@tonic-gate * Note: the returned character strings in ret_name and ret_value 461*7c478bd9Sstevel@tonic-gate * points to the stored character string in the parse string. Before 462*7c478bd9Sstevel@tonic-gate * this string value is returned to a calling application 463*7c478bd9Sstevel@tonic-gate * (profile_node_iterator is not an exported interface), it should be 464*7c478bd9Sstevel@tonic-gate * strdup()'ed. 465*7c478bd9Sstevel@tonic-gate */ 466*7c478bd9Sstevel@tonic-gate errcode_t profile_node_iterator(iter_p, ret_node, ret_name, ret_value) 467*7c478bd9Sstevel@tonic-gate void **iter_p; 468*7c478bd9Sstevel@tonic-gate struct profile_node **ret_node; 469*7c478bd9Sstevel@tonic-gate char **ret_name, **ret_value; 470*7c478bd9Sstevel@tonic-gate { 471*7c478bd9Sstevel@tonic-gate struct profile_iterator *iter = *iter_p; 472*7c478bd9Sstevel@tonic-gate struct profile_node *section, *p; 473*7c478bd9Sstevel@tonic-gate const char **cpp; 474*7c478bd9Sstevel@tonic-gate errcode_t retval; 475*7c478bd9Sstevel@tonic-gate int skip_num = 0; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 478*7c478bd9Sstevel@tonic-gate return PROF_MAGIC_ITERATOR; 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * If the file has changed, then the node pointer is invalid, 481*7c478bd9Sstevel@tonic-gate * so we'll have search the file again looking for it. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (iter->node && (iter->file->upd_serial != iter->file_serial)) { 484*7c478bd9Sstevel@tonic-gate iter->flags &= ~PROFILE_ITER_FINAL_SEEN; 485*7c478bd9Sstevel@tonic-gate skip_num = iter->num; 486*7c478bd9Sstevel@tonic-gate iter->node = 0; 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate get_new_file: 489*7c478bd9Sstevel@tonic-gate if (iter->node == 0) { 490*7c478bd9Sstevel@tonic-gate if (iter->file == 0 || 491*7c478bd9Sstevel@tonic-gate (iter->flags & PROFILE_ITER_FINAL_SEEN)) { 492*7c478bd9Sstevel@tonic-gate profile_node_iterator_free(iter_p); 493*7c478bd9Sstevel@tonic-gate if (ret_node) 494*7c478bd9Sstevel@tonic-gate *ret_node = 0; 495*7c478bd9Sstevel@tonic-gate if (ret_name) 496*7c478bd9Sstevel@tonic-gate *ret_name = 0; 497*7c478bd9Sstevel@tonic-gate if (ret_value) 498*7c478bd9Sstevel@tonic-gate *ret_value =0; 499*7c478bd9Sstevel@tonic-gate return 0; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate if ((retval = profile_update_file(iter->file))) { 502*7c478bd9Sstevel@tonic-gate profile_node_iterator_free(iter_p); 503*7c478bd9Sstevel@tonic-gate return retval; 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate iter->file_serial = iter->file->upd_serial; 506*7c478bd9Sstevel@tonic-gate /* 507*7c478bd9Sstevel@tonic-gate * Find the section to list if we are a LIST_SECTION, 508*7c478bd9Sstevel@tonic-gate * or find the containing section if not. 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate section = iter->file->root; 511*7c478bd9Sstevel@tonic-gate for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { 512*7c478bd9Sstevel@tonic-gate for (p=section->first_child; p; p = p->next) 513*7c478bd9Sstevel@tonic-gate if (!strcmp(p->name, *cpp) && !p->value) 514*7c478bd9Sstevel@tonic-gate break; 515*7c478bd9Sstevel@tonic-gate if (!p) { 516*7c478bd9Sstevel@tonic-gate section = 0; 517*7c478bd9Sstevel@tonic-gate break; 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate section = p; 520*7c478bd9Sstevel@tonic-gate if (p->final) 521*7c478bd9Sstevel@tonic-gate iter->flags |= PROFILE_ITER_FINAL_SEEN; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate if (!section) { 524*7c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 525*7c478bd9Sstevel@tonic-gate skip_num = 0; 526*7c478bd9Sstevel@tonic-gate goto get_new_file; 527*7c478bd9Sstevel@tonic-gate } 528*7c478bd9Sstevel@tonic-gate iter->name = *cpp; 529*7c478bd9Sstevel@tonic-gate iter->node = section->first_child; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * OK, now we know iter->node is set up correctly. Let's do 533*7c478bd9Sstevel@tonic-gate * the search. 534*7c478bd9Sstevel@tonic-gate */ 535*7c478bd9Sstevel@tonic-gate for (p = iter->node; p; p = p->next) { 536*7c478bd9Sstevel@tonic-gate if (iter->name && strcmp(p->name, iter->name)) 537*7c478bd9Sstevel@tonic-gate continue; 538*7c478bd9Sstevel@tonic-gate if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && 539*7c478bd9Sstevel@tonic-gate p->value) 540*7c478bd9Sstevel@tonic-gate continue; 541*7c478bd9Sstevel@tonic-gate if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && 542*7c478bd9Sstevel@tonic-gate !p->value) 543*7c478bd9Sstevel@tonic-gate continue; 544*7c478bd9Sstevel@tonic-gate if (skip_num > 0) { 545*7c478bd9Sstevel@tonic-gate skip_num--; 546*7c478bd9Sstevel@tonic-gate continue; 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate break; 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate iter->num++; 551*7c478bd9Sstevel@tonic-gate if (!p) { 552*7c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 553*7c478bd9Sstevel@tonic-gate iter->node = 0; 554*7c478bd9Sstevel@tonic-gate skip_num = 0; 555*7c478bd9Sstevel@tonic-gate goto get_new_file; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate if ((iter->node = p->next) == NULL) 558*7c478bd9Sstevel@tonic-gate iter->file = iter->file->next; 559*7c478bd9Sstevel@tonic-gate if (ret_node) 560*7c478bd9Sstevel@tonic-gate *ret_node = p; 561*7c478bd9Sstevel@tonic-gate if (ret_name) 562*7c478bd9Sstevel@tonic-gate *ret_name = p->name; 563*7c478bd9Sstevel@tonic-gate if (ret_value) 564*7c478bd9Sstevel@tonic-gate *ret_value = p->value; 565*7c478bd9Sstevel@tonic-gate return 0; 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* 569*7c478bd9Sstevel@tonic-gate * Remove a particular node. 570*7c478bd9Sstevel@tonic-gate * 571*7c478bd9Sstevel@tonic-gate * TYT, 2/25/99 572*7c478bd9Sstevel@tonic-gate */ 573*7c478bd9Sstevel@tonic-gate errcode_t profile_remove_node(node) 574*7c478bd9Sstevel@tonic-gate struct profile_node *node; 575*7c478bd9Sstevel@tonic-gate { 576*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (node->parent == 0) 579*7c478bd9Sstevel@tonic-gate return PROF_EINVAL; /* Can't remove the root! */ 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate if (node->prev) 582*7c478bd9Sstevel@tonic-gate node->prev->next = node->next; 583*7c478bd9Sstevel@tonic-gate else 584*7c478bd9Sstevel@tonic-gate node->parent->first_child = node->next; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate if (node->next) 587*7c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate profile_free_node(node); 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate return 0; 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* 595*7c478bd9Sstevel@tonic-gate * Set the value of a specific node containing a relation. 596*7c478bd9Sstevel@tonic-gate * 597*7c478bd9Sstevel@tonic-gate * TYT, 2/25/99 598*7c478bd9Sstevel@tonic-gate */ 599*7c478bd9Sstevel@tonic-gate errcode_t profile_set_relation_value(node, new_value) 600*7c478bd9Sstevel@tonic-gate struct profile_node *node; 601*7c478bd9Sstevel@tonic-gate const char *new_value; 602*7c478bd9Sstevel@tonic-gate { 603*7c478bd9Sstevel@tonic-gate char *cp; 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if (!node->value) 608*7c478bd9Sstevel@tonic-gate return PROF_SET_SECTION_VALUE; 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate cp = (char *) malloc(strlen(new_value)+1); 611*7c478bd9Sstevel@tonic-gate if (!cp) 612*7c478bd9Sstevel@tonic-gate return ENOMEM; 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate strcpy(cp, new_value); 615*7c478bd9Sstevel@tonic-gate free(node->value); 616*7c478bd9Sstevel@tonic-gate node->value = cp; 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate return 0; 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate /* 622*7c478bd9Sstevel@tonic-gate * Rename a specific node 623*7c478bd9Sstevel@tonic-gate * 624*7c478bd9Sstevel@tonic-gate * TYT 2/25/99 625*7c478bd9Sstevel@tonic-gate */ 626*7c478bd9Sstevel@tonic-gate errcode_t profile_rename_node(node, new_name) 627*7c478bd9Sstevel@tonic-gate struct profile_node *node; 628*7c478bd9Sstevel@tonic-gate const char *new_name; 629*7c478bd9Sstevel@tonic-gate { 630*7c478bd9Sstevel@tonic-gate char *new_string; 631*7c478bd9Sstevel@tonic-gate struct profile_node *p, *last; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate CHECK_MAGIC(node); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate if (strcmp(new_name, node->name) == 0) 636*7c478bd9Sstevel@tonic-gate return 0; /* It's the same name, return */ 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate /* 639*7c478bd9Sstevel@tonic-gate * Make sure we can allocate memory for the new name, first! 640*7c478bd9Sstevel@tonic-gate */ 641*7c478bd9Sstevel@tonic-gate new_string = (char *) malloc(strlen(new_name)+1); 642*7c478bd9Sstevel@tonic-gate if (!new_string) 643*7c478bd9Sstevel@tonic-gate return ENOMEM; 644*7c478bd9Sstevel@tonic-gate strcpy(new_string, new_name); 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * Find the place to where the new node should go. We look 648*7c478bd9Sstevel@tonic-gate * for the place *after* the last match of the node name, 649*7c478bd9Sstevel@tonic-gate * since order matters. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) { 652*7c478bd9Sstevel@tonic-gate if (strcmp(p->name, new_name) > 0) 653*7c478bd9Sstevel@tonic-gate break; 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * If we need to move the node, do it now. 658*7c478bd9Sstevel@tonic-gate */ 659*7c478bd9Sstevel@tonic-gate if ((p != node) && (last != node)) { 660*7c478bd9Sstevel@tonic-gate /* 661*7c478bd9Sstevel@tonic-gate * OK, let's detach the node 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate if (node->prev) 664*7c478bd9Sstevel@tonic-gate node->prev->next = node->next; 665*7c478bd9Sstevel@tonic-gate else 666*7c478bd9Sstevel@tonic-gate node->parent->first_child = node->next; 667*7c478bd9Sstevel@tonic-gate if (node->next) 668*7c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * Now let's reattach it in the right place. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate if (p) 674*7c478bd9Sstevel@tonic-gate p->prev = node; 675*7c478bd9Sstevel@tonic-gate if (last) 676*7c478bd9Sstevel@tonic-gate last->next = node; 677*7c478bd9Sstevel@tonic-gate else 678*7c478bd9Sstevel@tonic-gate node->parent->first_child = node; 679*7c478bd9Sstevel@tonic-gate node->next = p; 680*7c478bd9Sstevel@tonic-gate node->prev = last; 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate free(node->name); 684*7c478bd9Sstevel@tonic-gate node->name = new_string; 685*7c478bd9Sstevel@tonic-gate return 0; 686*7c478bd9Sstevel@tonic-gate } 687