2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * prof_set.c --- routines that expose the public interfaces for
2N/A * inserting, updating and deleting items from the profile.
2N/A *
2N/A * WARNING: These routines only look at the first file opened in the
2N/A * profile. It's not clear how to handle multiple files, actually.
2N/A * In the future it may be necessary to modify this public interface,
2N/A * or possibly add higher level functions to support this correctly.
2N/A *
2N/A * WARNING: We're not yet doing locking yet, either.
2N/A *
2N/A */
2N/A
2N/A#include "prof_int.h"
2N/A
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#ifdef HAVE_STDLIB_H
2N/A#include <stdlib.h>
2N/A#endif
2N/A#include <errno.h>
2N/A
2N/Astatic errcode_t rw_setup(profile_t profile)
2N/A{
2N/A prf_file_t file;
2N/A errcode_t retval = 0;
2N/A
2N/A if (!profile)
2N/A return PROF_NO_PROFILE;
2N/A
2N/A if (profile->magic != PROF_MAGIC_PROFILE)
2N/A return PROF_MAGIC_PROFILE;
2N/A
2N/A file = profile->first_file;
2N/A
2N/A retval = profile_lock_global();
2N/A if (retval)
2N/A return retval;
2N/A
2N/A /* Don't update the file if we've already made modifications */
2N/A if (file->data->flags & PROFILE_FILE_DIRTY) {
2N/A profile_unlock_global();
2N/A return 0;
2N/A }
2N/A
2N/A if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
2N/A prf_data_t new_data;
2N/A new_data = profile_make_prf_data(file->data->filespec);
2N/A if (new_data == NULL) {
2N/A retval = ENOMEM;
2N/A } else {
2N/A retval = k5_mutex_init(&new_data->lock);
2N/A if (retval == 0) {
2N/A new_data->root = NULL;
2N/A new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED;
2N/A new_data->timestamp = 0;
2N/A new_data->upd_serial = file->data->upd_serial;
2N/A }
2N/A }
2N/A
2N/A if (retval != 0) {
2N/A profile_unlock_global();
2N/A free(new_data);
2N/A return retval;
2N/A }
2N/A profile_dereference_data_locked(file->data);
2N/A file->data = new_data;
2N/A }
2N/A
2N/A profile_unlock_global();
2N/A retval = profile_update_file(file);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Delete or update a particular child node
2N/A *
2N/A * ADL - 2/23/99, rewritten TYT 2/25/99
2N/A */
2N/Aerrcode_t KRB5_CALLCONV
2N/Aprofile_update_relation(profile_t profile, const char **names,
2N/A const char *old_value, const char *new_value)
2N/A{
2N/A errcode_t retval;
2N/A struct profile_node *section, *node;
2N/A void *state;
2N/A const char **cpp;
2N/A
2N/A retval = rw_setup(profile);
2N/A if (retval)
2N/A return retval;
2N/A
2N/A if (names == 0 || names[0] == 0 || names[1] == 0)
2N/A return PROF_BAD_NAMESET;
2N/A
2N/A if (!old_value || !*old_value)
2N/A return PROF_EINVAL;
2N/A
2N/A retval = k5_mutex_lock(&profile->first_file->data->lock);
2N/A if (retval)
2N/A return retval;
2N/A section = profile->first_file->data->root;
2N/A for (cpp = names; cpp[1]; cpp++) {
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, 0, 1,
2N/A &state, &section);
2N/A if (retval) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A }
2N/A }
2N/A
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
2N/A if (retval == 0) {
2N/A if (new_value)
2N/A retval = profile_set_relation_value(node, new_value);
2N/A else
2N/A retval = profile_remove_node(node);
2N/A }
2N/A if (retval == 0)
2N/A profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Clear a particular all of the relations with a specific name.
2N/A *
2N/A * TYT - 2/25/99
2N/A */
2N/Aerrcode_t KRB5_CALLCONV
2N/Aprofile_clear_relation(profile_t profile, const char **names)
2N/A{
2N/A errcode_t retval;
2N/A struct profile_node *section, *node;
2N/A void *state;
2N/A const char **cpp;
2N/A
2N/A retval = rw_setup(profile);
2N/A if (retval)
2N/A return retval;
2N/A
2N/A if (names == 0 || names[0] == 0 || names[1] == 0)
2N/A return PROF_BAD_NAMESET;
2N/A
2N/A section = profile->first_file->data->root;
2N/A for (cpp = names; cpp[1]; cpp++) {
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, 0, 1,
2N/A &state, &section);
2N/A if (retval)
2N/A return retval;
2N/A }
2N/A
2N/A state = 0;
2N/A do {
2N/A retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
2N/A if (retval)
2N/A return retval;
2N/A retval = profile_remove_node(node);
2N/A if (retval)
2N/A return retval;
2N/A } while (state);
2N/A
2N/A profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
2N/A
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Rename a particular section; if the new_section name is NULL,
2N/A * delete it.
2N/A *
2N/A * ADL - 2/23/99, rewritten TYT 2/25/99
2N/A */
2N/Aerrcode_t KRB5_CALLCONV
2N/Aprofile_rename_section(profile_t profile, const char **names,
2N/A const char *new_name)
2N/A{
2N/A errcode_t retval;
2N/A struct profile_node *section, *node;
2N/A void *state;
2N/A const char **cpp;
2N/A
2N/A retval = rw_setup(profile);
2N/A if (retval)
2N/A return retval;
2N/A
2N/A if (names == 0 || names[0] == 0 || names[1] == 0)
2N/A return PROF_BAD_NAMESET;
2N/A
2N/A retval = k5_mutex_lock(&profile->first_file->data->lock);
2N/A if (retval)
2N/A return retval;
2N/A section = profile->first_file->data->root;
2N/A for (cpp = names; cpp[1]; cpp++) {
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, 0, 1,
2N/A &state, &section);
2N/A if (retval) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A }
2N/A }
2N/A
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
2N/A if (retval == 0) {
2N/A if (new_name)
2N/A retval = profile_rename_node(node, new_name);
2N/A else
2N/A retval = profile_remove_node(node);
2N/A }
2N/A if (retval == 0)
2N/A profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A}
2N/A
2N/A/*
2N/A * Insert a new relation. If the new_value argument is NULL, then
2N/A * create a new section instead.
2N/A *
2N/A * Note: if the intermediate sections do not exist, this function will
2N/A * automatically create them.
2N/A *
2N/A * ADL - 2/23/99, rewritten TYT 2/25/99
2N/A */
2N/Aerrcode_t KRB5_CALLCONV
2N/Aprofile_add_relation(profile_t profile, const char **names,
2N/A const char *new_value)
2N/A{
2N/A errcode_t retval;
2N/A struct profile_node *section;
2N/A const char **cpp;
2N/A void *state;
2N/A
2N/A retval = rw_setup(profile);
2N/A if (retval)
2N/A return retval;
2N/A
2N/A if (names == 0 || names[0] == 0 || names[1] == 0)
2N/A return PROF_BAD_NAMESET;
2N/A
2N/A retval = k5_mutex_lock(&profile->first_file->data->lock);
2N/A if (retval)
2N/A return retval;
2N/A section = profile->first_file->data->root;
2N/A for (cpp = names; cpp[1]; cpp++) {
2N/A state = 0;
2N/A retval = profile_find_node(section, *cpp, 0, 1,
2N/A &state, &section);
2N/A if (retval == PROF_NO_SECTION)
2N/A retval = profile_add_node(section, *cpp, 0, &section);
2N/A if (retval) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A }
2N/A }
2N/A
2N/A if (new_value == 0) {
2N/A retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
2N/A if (retval == 0) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return PROF_EXISTS;
2N/A } else if (retval != PROF_NO_SECTION) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A }
2N/A }
2N/A
2N/A retval = profile_add_node(section, *cpp, new_value, 0);
2N/A if (retval) {
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return retval;
2N/A }
2N/A
2N/A profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
2N/A k5_mutex_unlock(&profile->first_file->data->lock);
2N/A return 0;
2N/A}