1/* 2 * prof_set.c --- routines that expose the public interfaces for 3 * inserting, updating and deleting items from the profile. 4 * 5 * WARNING: These routines only look at the first file opened in the 6 * profile. It's not clear how to handle multiple files, actually. 7 * In the future it may be necessary to modify this public interface, 8 * or possibly add higher level functions to support this correctly. 9 * 10 * WARNING: We're not yet doing locking yet, either. 11 * 12 */ 13 14#include "prof_int.h" 15 16#include <stdio.h> 17#include <string.h> 18#ifdef HAVE_STDLIB_H 19#include <stdlib.h> 20#endif 21#include <errno.h> 22 23static errcode_t rw_setup(profile_t profile) 24{ 25 prf_file_t file; 26 errcode_t retval = 0; 27 28 if (!profile) 29 return PROF_NO_PROFILE; 30 31 if (profile->magic != PROF_MAGIC_PROFILE) 32 return PROF_MAGIC_PROFILE; 33 34 file = profile->first_file; 35 36 retval = profile_lock_global(); 37 if (retval) 38 return retval; 39 40 /* Don't update the file if we've already made modifications */ 41 if (file->data->flags & PROFILE_FILE_DIRTY) { 42 profile_unlock_global(); 43 return 0; 44 } 45 46 if ((file->data->flags & PROFILE_FILE_SHARED) != 0) { 47 prf_data_t new_data; 48 new_data = profile_make_prf_data(file->data->filespec); 49 if (new_data == NULL) { 50 retval = ENOMEM; 51 } else { 52 retval = pthread_mutex_init(&new_data->lock, NULL); 53 if (retval == 0) { 54 new_data->root = NULL; 55 new_data->flags = file->data->flags & ~(PROFILE_FILE_SHARED | PROFILE_FILE_HAVE_DATA); 56 new_data->timestamp = 0; 57 new_data->upd_serial = file->data->upd_serial; 58 } 59 } 60 61 if (retval != 0) { 62 profile_unlock_global(); 63 free(new_data); 64 return retval; 65 } 66 profile_dereference_data_locked(file->data); 67 file->data = new_data; 68 } 69 70 profile_unlock_global(); 71 retval = profile_update_file_data(file->data); 72 73 return retval; 74} 75 76 77/* 78 * Delete or update a particular child node 79 * 80 * ADL - 2/23/99, rewritten TYT 2/25/99 81 */ 82errcode_t KRB5_CALLCONV 83profile_update_relation(profile_t profile, const char **names, 84 const char *old_value, const char *new_value) 85{ 86 errcode_t retval; 87 struct profile_node *section, *node; 88 void *state; 89 const char **cpp; 90 91 retval = rw_setup(profile); 92 if (retval) 93 return retval; 94 95 if (names == 0 || names[0] == 0 || names[1] == 0) 96 return PROF_BAD_NAMESET; 97 98 if (!old_value || !*old_value) 99 return PROF_EINVAL; 100 101 retval = pthread_mutex_lock(&profile->first_file->data->lock); 102 if (retval) 103 return retval; 104 section = profile->first_file->data->root; 105 for (cpp = names; cpp[1]; cpp++) { 106 state = 0; 107 retval = profile_find_node(section, *cpp, 0, 1, 108 &state, §ion); 109 if (retval) { 110 pthread_mutex_unlock(&profile->first_file->data->lock); 111 return retval; 112 } 113 } 114 115 state = 0; 116 retval = profile_find_node(section, *cpp, old_value, 0, &state, &node); 117 if (retval == 0) { 118 if (new_value) 119 retval = profile_set_relation_value(node, new_value); 120 else 121 retval = profile_remove_node(node); 122 } 123 if (retval == 0) 124 profile->first_file->data->flags |= PROFILE_FILE_DIRTY; 125 pthread_mutex_unlock(&profile->first_file->data->lock); 126 127 return retval; 128} 129 130/* 131 * Clear a particular all of the relations with a specific name. 132 * 133 * TYT - 2/25/99 134 */ 135errcode_t KRB5_CALLCONV 136profile_clear_relation(profile_t profile, const char **names) 137{ 138 errcode_t retval; 139 struct profile_node *section, *node; 140 void *state; 141 const char **cpp; 142 143 retval = rw_setup(profile); 144 if (retval) 145 return retval; 146 147 if (names == 0 || names[0] == 0 || names[1] == 0) 148 return PROF_BAD_NAMESET; 149 150 section = profile->first_file->data->root; 151 for (cpp = names; cpp[1]; cpp++) { 152 state = 0; 153 retval = profile_find_node(section, *cpp, 0, 1, 154 &state, §ion); 155 if (retval) 156 return retval; 157 } 158 159 state = 0; 160 do { 161 retval = profile_find_node(section, *cpp, 0, 0, &state, &node); 162 if (retval) 163 return retval; 164 retval = profile_remove_node(node); 165 if (retval) 166 return retval; 167 } while (state); 168 169 profile->first_file->data->flags |= PROFILE_FILE_DIRTY; 170 171 return 0; 172} 173 174/* 175 * Rename a particular section; if the new_section name is NULL, 176 * delete it. 177 * 178 * ADL - 2/23/99, rewritten TYT 2/25/99 179 */ 180errcode_t KRB5_CALLCONV 181profile_rename_section(profile_t profile, const char **names, 182 const char *new_name) 183{ 184 errcode_t retval; 185 struct profile_node *section, *node; 186 void *state; 187 const char **cpp; 188 189 retval = rw_setup(profile); 190 if (retval) 191 return retval; 192 193 if (names == 0 || names[0] == 0 || names[1] == 0) 194 return PROF_BAD_NAMESET; 195 196 retval = pthread_mutex_lock(&profile->first_file->data->lock); 197 if (retval) 198 return retval; 199 section = profile->first_file->data->root; 200 for (cpp = names; cpp[1]; cpp++) { 201 state = 0; 202 retval = profile_find_node(section, *cpp, 0, 1, 203 &state, §ion); 204 if (retval) { 205 pthread_mutex_unlock(&profile->first_file->data->lock); 206 return retval; 207 } 208 } 209 210 state = 0; 211 retval = profile_find_node(section, *cpp, 0, 1, &state, &node); 212 if (retval == 0) { 213 if (new_name) 214 retval = profile_rename_node(node, new_name); 215 else 216 retval = profile_remove_node(node); 217 } 218 if (retval == 0) 219 profile->first_file->data->flags |= PROFILE_FILE_DIRTY; 220 pthread_mutex_unlock(&profile->first_file->data->lock); 221 return retval; 222} 223 224/* 225 * Insert a new relation. If the new_value argument is NULL, then 226 * create a new section instead. 227 * 228 * Note: if the intermediate sections do not exist, this function will 229 * automatically create them. 230 * 231 * ADL - 2/23/99, rewritten TYT 2/25/99 232 */ 233errcode_t KRB5_CALLCONV 234profile_add_relation(profile_t profile, const char **names, 235 const char *new_value) 236{ 237 errcode_t retval; 238 struct profile_node *section; 239 const char **cpp; 240 void *state; 241 242 retval = rw_setup(profile); 243 if (retval) 244 return retval; 245 246 if (names == 0 || names[0] == 0 || names[1] == 0) 247 return PROF_BAD_NAMESET; 248 249 retval = pthread_mutex_lock(&profile->first_file->data->lock); 250 if (retval) 251 return retval; 252 section = profile->first_file->data->root; 253 for (cpp = names; cpp[1]; cpp++) { 254 state = 0; 255 retval = profile_find_node(section, *cpp, 0, 1, 256 &state, §ion); 257 if (retval == PROF_NO_SECTION) 258 retval = profile_add_node(section, *cpp, 0, §ion); 259 if (retval) { 260 pthread_mutex_unlock(&profile->first_file->data->lock); 261 return retval; 262 } 263 } 264 265 if (new_value == 0) { 266 retval = profile_find_node(section, *cpp, 0, 1, &state, 0); 267 if (retval == 0) { 268 pthread_mutex_unlock(&profile->first_file->data->lock); 269 return PROF_EXISTS; 270 } else if (retval != PROF_NO_SECTION) { 271 pthread_mutex_unlock(&profile->first_file->data->lock); 272 return retval; 273 } 274 } 275 276 retval = profile_add_node(section, *cpp, new_value, 0); 277 if (retval) { 278 pthread_mutex_unlock(&profile->first_file->data->lock); 279 return retval; 280 } 281 282 profile->first_file->data->flags |= PROFILE_FILE_DIRTY; 283 pthread_mutex_unlock(&profile->first_file->data->lock); 284 return 0; 285} 286 287