/* $CoreSDI: resource.c,v 1.29 2001/10/05 23:14:58 claudio Exp $ */ /* * Copyright (c) 2000, 2001, Core SDI S.A., Argentina * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither name of the Core SDI S.A. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Resources Generic Interface * Author: Claudio Castiglia */ #include #ifndef WIN32 #include #include #include #include #endif /* WIN32 */ #include #include #include #include #include #include "sysdep.h" #include "packet.h" #include "version.h" #include "audconf.h" #include "resource.h" #include "modtypes.h" #include "modules.h" #include "log.h" /* Exported by resource modules */ static int (*_resmod_check) (const char *); static int (*_resmod_load) (RESLIST *); static int (*_resmod_save) (const RESLIST *); static int (*_resmod_remove) (const char *); /* Resources module handler */ static void *_res_handle = NULL; /* * res_module_init(): * Init resource system: load specified resource module. * Return 0 on success or -1 on error and set errno. */ int res_module_init(const char *name) { char fullname[MAXPATHLEN] = { "" }; if (name == NULL) return (-1); full_module_pathname(fullname, "res", name); log_debug("Resources api: Initializing %s.", fullname); _res_handle = load_module(fullname); if (_res_handle == NULL) return (-1); _resmod_check = load_function(_res_handle, SYMBOL_PREFIX "check", 1); _resmod_load = load_function(_res_handle, SYMBOL_PREFIX "load", 1); _resmod_save = load_function(_res_handle, SYMBOL_PREFIX "save", 1); _resmod_remove = load_function(_res_handle, SYMBOL_PREFIX "remove", 1); if (_resmod_check == NULL || _resmod_load == NULL || _resmod_save == NULL || _resmod_remove == NULL) { res_module_release(); return (-1); } return (0); } /* * res_module_release(): * Close resource module. */ void res_module_release() { if (_res_handle != NULL) { dlclose(_res_handle); _res_handle = NULL; } } /* * res_check_list(): * Check if list exists. * Return 1 if specified list exists or 0 if not. This function * does not load the list, just test its existense. */ int res_check_list(const char *listname) { if (listname != NULL) return (_resmod_check(listname)); return (0); } /* * res_open_list(): * Create a resource list. * Return a pointer to the new RESLIST structure; * on error NULL is returned and errno set. * mode values: * RES_READ : Create list, read existing data; * RES_FORCEREAD: Create list only if data exists; * RES_NOTREAD : Create list, do not read data. */ RESLIST * res_open_list(const char *listname, int mode) { RESLIST *rlist; log_debug("Resources api: Opening %s, mode %i.", listname, mode); rlist = (RESLIST *) calloc(1, sizeof(RESLIST)); if (rlist == NULL) return (NULL); strlcpy(rlist->lname, listname, sizeof(rlist->lname)); switch (mode) { case RES_READ: case RES_FORCEREAD: if (_resmod_load(rlist) < 0) { if (mode == RES_FORCEREAD) { free(rlist); return (NULL); } } break; case RES_NOTREAD: default: break; } return (rlist); } /* * res_release_list(): * Release a list (flush pending data, close it, and * free allocated mem). */ void res_release_list(RESLIST *rlist) { RESOURCE *r; RESLIST *list, *pl; if (rlist != NULL) { if (_resmod_save(rlist) < 0) log_err("resource: save: %s: %s.", rlist->lname, strerror(errno)); for (list = rlist; list != NULL;) { for (r = list->first_res; r != NULL;) { if (r->name != NULL) free(r->name); if (r->data != NULL) free(r->data); if ( (r = r->next) != NULL) if (r->prev != NULL) free(r->prev); } pl = list; list = list->lnext; free(pl); } } } /* * res_remove_list(): * Remove a resource list. */ int res_remove_list(const char *listname) { if (listname == NULL) { errno = EINVAL; return (-1); } return (_resmod_remove(listname)); } /* * res_save_list(): * Force the resource list to be saved (flushed); * return 0 on success and -1 on error (in this case, the error * code depends on the resource module used). */ int res_save_list(const RESLIST *rlist) { if (rlist == NULL) { errno = EINVAL; return (-1); } return (_resmod_save(rlist)); } /* * res_add(): * Add a new resource into the list; * return 0 on success and < 0 on error (and set errno). * Returned errno values: * EINVAL: Invalid parameters * EEXIST: Resource exists * and those possible returned by calloc(3). * If you add a new and, you want this resource to be available * on next program instances, you should save the entire * resource list using the res_save() function. */ int res_add(RESLIST *rlist, const char *rname, const void *data, ssize_t dsize) { RESOURCE *r; if (rlist == NULL || rname == NULL || data == NULL || dsize <= 0) { errno = EINVAL; return (-1); } if (res_find(rlist, rname) != NULL) { errno = EEXIST; return (-1); } /* Allocate memory for a new resource */ r = (RESOURCE *) calloc(1, sizeof(RESOURCE)); if (r == NULL) return (-1); r->name = strdup(rname); r->data = malloc(dsize); if (r->data == NULL) { if (r->name != NULL) free(r->name); free(r); return (-1); } /* Copy data into the new resource */ memcpy(r->data, data, dsize); r->dsize = dsize; /* Insert the new resource into the list */ if (rlist->first_res == NULL) rlist->first_res = r; r->prev = rlist->last_res; rlist->last_res = r; if (r->prev != NULL) r->prev->next = r; return (0); } /* * res_remove(): * Remove a resource from the list (and from memory). * If you want the changes to be available in next program * instances, you should save the resource list using res_save() * function. */ void res_remove(RESLIST *rlist, const char *rname) { RESOURCE *r; if (rlist != NULL && rname != NULL) if ( (r = res_find(rlist, rname)) != NULL) { if (r->next != NULL) r->next->prev = r->prev; if (r->prev != NULL) r->prev->next = r->next; if (rlist->first_res == r) rlist->first_res = (r->prev != NULL) ? r->prev : r->next; if (rlist->last_res == r) rlist->last_res = (r->next != NULL) ? r->next : r->prev; /* * XXX modified rlist flag indicates to res_save() * that _all_ list must be saved because any * resources was deleted from the list. */ rlist->flags |= RF_MODIFIED; /* free resource */ free(r->name); free(r->data); free(r); } } /* * res_replace(): * Replace an existing resource data; * return 0 on success and < 0 on error (and set errno). * Returned errno values: * EINVAL: Invalid parameters * and those possible returned by malloc(3). * If you want the changes to be available on next program * instances, you should save the resource list using res_save() * function. * NOTE: replaced data resource should belong to the list otherwise * changes will not be available on next program instances. */ int res_replace(RESLIST *rlist, RESOURCE *r, const void *data, ssize_t dsize) { void *new_data; if (rlist == NULL || r == NULL || data == NULL || dsize <= 0) { errno = EINVAL; return (-1); } if ( (new_data = malloc(dsize)) == NULL) return (-1); if (r->data) free(r->data); memcpy(new_data, data, dsize); r->data = new_data; r->dsize = dsize; rlist->flags |= RF_MODIFIED; /* at least one resource was changed */ /* XXX: wrong! with this, save will believe that all should be saved and not only those modified resources. Must be more specific. */ return (0); } /* * res_find(): * Search for a resource into the resource list; * return NULL if no match. */ RESOURCE * res_find(const RESLIST *rlist, const char *rname) { RESOURCE *r; const RESLIST *list; if (rlist == NULL || rname == NULL) return (NULL); for (list = rlist; list != NULL; list = list->lnext) for (r = list->first_res; r != NULL; r = r->next) if (!strcmp(rname, r->name)) return (r); return (NULL); }