/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /******************************************************************************* ** ** dtfns.c ** ** $XConsortium: dtfns.c /main/3 1995/11/03 10:37:35 rswiston $ ** ** RESTRICTED CONFIDENTIAL INFORMATION: ** ** The information in this document is subject to special ** restrictions in a confidential disclosure agreement between ** HP, IBM, Sun, USL, SCO and Univel. Do not distribute this ** document outside HP, IBM, Sun, USL, SCO, or Univel without ** Sun's specific written approval. This document and all copies ** and derivative works thereof must be returned or destroyed at ** Sun's request. ** ** Copyright 1993 Sun Microsystems, Inc. All rights reserved. ** *******************************************************************************/ /* * * (c) Copyright 1993, 1994 Hewlett-Packard Company * * (c) Copyright 1993, 1994 International Business Machines Corp. * * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * * (c) Copyright 1993, 1994 Novell, Inc. * */ #ifndef lint static char sccsid[] = "@(#)dtfns.c 1.3 94/11/07 Copyr 1993 Sun Microsystems, Inc."; #endif /* * Copyright 1993 Sun Microsystems, Inc. All rights reserved */ #ifdef FNS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "util.h" #include "dtfns.h" extern char *strdup(const char *); /* * Names found in the initial context. Used by isa_helix_name() * * XXX We have a bug here. If a string happens to start with * thisuser, myorg, etc we'll recognize it as an FNS name even * though it may not be one. */ static char *initial_context_names[] = { "user:", "thisuser", "org:", "site:", "myorg", "hostorg", "host:", NULL, }; static void *libfns_handle = NULL; static int initialized = 0; static NS_Context_t *initial_ctx = NULL; /* * These are dynamically bound entry points into libfns. We dlopen() * libfns so that cm can still run even if libfns does not exist */ static NS_Context_t *(*NS_Context_get_initial_p)(NS_ContextStatus_t *); static NS_ContextStatus_t *(*NS_ContextStatus_new_p)(void); static void (*NS_ContextStatus_delete_p)(NS_ContextStatus_t *); static NS_Reference_t *(*NS_Context_lookup_p)(const NS_Context_t *, const NS_CompositeName_t *, NS_ContextStatus_t *); static int (*NS_Context_bind_p)(const NS_Context_t *, const NS_CompositeName_t *, const NS_Reference_t *, unsigned, NS_ContextStatus_t *); static NS_Reference_t *(*NS_Reference_new_p)(const NS_String_t *); static void (*NS_Reference_delete_p)(const NS_Reference_t *); static NS_String_t *(*NS_Reference_type_p)(const NS_Reference_t *); static int (*NS_Reference_count_p)(const NS_Reference_t *); static NS_ReferenceAddress_t *(*NS_Reference_first_p)(const NS_Reference_t *, void **); static NS_ReferenceAddress_t *(*NS_Reference_next_p)(const NS_Reference_t *, void **); static int (*NS_Reference_append_addr_p)(NS_Reference_t *, const NS_ReferenceAddress_t *); static int (*NS_Reference_prepend_addr_p)(NS_Reference_t *, const NS_ReferenceAddress_t *); static int (*NS_Reference_insert_addr_p)(NS_Reference_t *, void **, const NS_ReferenceAddress_t *); static int (*NS_Reference_delete_addr_p)(NS_Reference_t *, void **); static void (*NS_ReferenceAddress_delete_p)( NS_ReferenceAddress_t *); static NS_ReferenceAddress_t *(*NS_ReferenceAddress_new_p)(const NS_String_t *, unsigned, const void *); static void * (*NS_ReferenceAddress_data_p)(const NS_ReferenceAddress_t *); static unsigned (*NS_ReferenceAddress_length_p)(const NS_ReferenceAddress_t *); static NS_String_t *(*NS_ReferenceAddress_type_p)(const NS_ReferenceAddress_t*); static const char * (*NS_String_cstring_p)(const NS_String_t *); static NS_String_t * (*NS_String_from_cstring_p)(const char *); static NS_CompositeName_t * (*NS_CompositeName_from_cstring_p)(const char *); static int get_helix_service_name(const char *name, const char *service, const char *service_type, char **buf); /* * Initialization. * * Load libfns (with dlopen) and bind in the entry points we use (with dlsym). * * We dynamically load the FNS library so that we don't have an explicit * dependency on it. This lets us run on systems which do not have FNS * installed * * Returns * 0 FNS not available * 1 Success */ int dtfns_init(void) { char *libfns = FNS_LIBRARY; int error; if (libfns_handle != NULL) { return 1; } initialized = TRUE; libfns_handle = dlopen(libfns, RTLD_LAZY); if (libfns_handle == NULL) { #ifdef CM_DEBUG char *s = dlerror(); if (s == NULL) { DP(("Could not dlopen %s\n", libfns)); } else { DP(("Could not dlopen %s: %s\n", libfns, s)); } #endif return 0; } NS_Context_get_initial_p = (NS_Context_t *(*)(NS_ContextStatus_t *)) dlsym(libfns_handle, "NS_Context_get_initial"); NS_ContextStatus_new_p = (NS_ContextStatus_t *(*)(void)) dlsym(libfns_handle, "NS_ContextStatus_new"); NS_ContextStatus_delete_p = (void(*)(NS_ContextStatus_t *)) dlsym(libfns_handle, "NS_ContextStatus_delete"); NS_Context_lookup_p = (NS_Reference_t *(*)(const NS_Context_t *, const NS_CompositeName_t *, NS_ContextStatus_t *)) dlsym(libfns_handle, "NS_Context_lookup"); NS_Context_bind_p = (int(*)(const NS_Context_t *, const NS_CompositeName_t *, const NS_Reference_t *, unsigned, NS_ContextStatus_t *)) dlsym(libfns_handle, "NS_Context_bind"); NS_Reference_new_p = (NS_Reference_t *(*)(const NS_String_t *)) dlsym(libfns_handle, "NS_Reference_new"); NS_Reference_delete_p = (void(*)(const NS_Reference_t *)) dlsym(libfns_handle, "NS_Reference_delete");; NS_Reference_type_p = (NS_String_t *(*)(const NS_Reference_t *)) dlsym(libfns_handle, "NS_Reference_type"); NS_Reference_count_p = (int(*)(const NS_Reference_t *)) dlsym(libfns_handle, "NS_Reference_count"); NS_Reference_first_p = (NS_ReferenceAddress_t *(*) (const NS_Reference_t *, void **)) dlsym(libfns_handle, "NS_Reference_first"); NS_Reference_next_p = (NS_ReferenceAddress_t *(*) (const NS_Reference_t *, void **)) dlsym(libfns_handle, "NS_Reference_next"); NS_Reference_append_addr_p = (int(*)(NS_Reference_t *, const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_Reference_append_addr"); NS_Reference_prepend_addr_p = (int(*)(NS_Reference_t *, const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_Reference_prepend_addr"); NS_Reference_insert_addr_p = (int(*)(NS_Reference_t *, void **, const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_Reference_insert_addr"); NS_Reference_delete_addr_p = (int(*)(NS_Reference_t *, void **)) dlsym(libfns_handle, "NS_Reference_delete_addr"); NS_ReferenceAddress_delete_p = (void(*)(NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_ReferenceAddress_delete"); NS_ReferenceAddress_new_p = (NS_ReferenceAddress_t *(*) (const NS_String_t *, unsigned, const void *)) dlsym(libfns_handle, "NS_ReferenceAddress_new"); NS_ReferenceAddress_data_p = (void *(*)(const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_ReferenceAddress_data"); NS_ReferenceAddress_length_p = (unsigned(*) (const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_ReferenceAddress_length"); NS_ReferenceAddress_type_p = (NS_String_t *(*) (const NS_ReferenceAddress_t *)) dlsym(libfns_handle, "NS_ReferenceAddress_type"); NS_String_cstring_p = (const char *(*)(const NS_String_t *)) dlsym(libfns_handle, "NS_String_cstring"); NS_String_from_cstring_p = (NS_String_t * (*)(const char *)) dlsym(libfns_handle, "NS_String_from_cstring"); NS_CompositeName_from_cstring_p =(NS_CompositeName_t *(*)(const char *)) dlsym(libfns_handle, "NS_CompositeName_from_cstring"); return 1; } /* * Check if FNS is available for use. * * You must call dfsinit() before calling this routine. * * First call to this routine may be costly as we get the initial context. * Subsequent calls are very cheap. * * Returns * 1 Yes, FNS is available. * 0 No, FNS is not available. * -1 You haven't called dtfns_init(). */ int dtfns_available(void) { static int available; static int called; if (called) { return available; } if (libfns_handle != NULL) { /* * libfns has been dlopened. Now see if an FNS namespace * is reachable by getting the initial context. */ if (dtfns_get_initial_ctx() == NULL) { available = 0; } else { available = 1; } } else if (initialized) { /* dlopen must have failed. FNS is not installed */ available = 0; } else { available = -1; } called = 1; return available; } /* * Get the initial context. This routine caches the initial context. * The first call to this routine may be costly, be subsequent calls * are very cheap. */ NS_Context_t * dtfns_get_initial_ctx(void) { DP(("dtfns_get_initial_ctx: Getting initial context\n")); if (initial_ctx == NULL) { NS_ContextStatus_t * status; status = (*NS_ContextStatus_new_p)(); initial_ctx = (*NS_Context_get_initial_p)(status); (*NS_ContextStatus_delete_p)(status); } return initial_ctx; } /* * Generate a full Helix name for a service. * * 'name' may be a relative Helix name. I.e.: * smith * smith:service * smith:service:calendar * In this case dtfns_service_name() will use the type, service and org * parameters (if needed) to construct the full Helix name. * * 'name' may also be an absolute Helix name. I.e.: * user:smith * org:ssi.eng:user:smith * user:smith:service * In this case dtfns_service_name() will use the type and service * parameters (if needed) to construct the full Helix name. The org * parameter should be NULL (since the organization is already * determined by the absolute Helix name). * * 'type' specifies the type of object 'name' refers to (ie "user"). * * 'service' specifies what service is desired (ie "calendar"). * * 'service_type' specifies the reference type of the service * (ie SUNW_fns_calendar); * * 'org' is the organization name. This must be NULL if 'name' is * an absolute Helix name. 'org' may be NULL in all other cases if the * default organization is to be used. * * 'buf' is a buffer provided by the caller in which the expanded name * is placed. * * 'size' is the size of 'buf' * * * The string returned in buf may be used in calls to dtfns_lookup_str() and * dtfns_lookup_ref(). * * Returns * -1 Name not found / Error * 0 FNS not available * 1 Success */ int dtfns_service_name( const char *name, /* Name to lookup */ const char *type, /* Type of object name is (ie "user") */ const char *service, /* Service name (ie "calendar") */ const char *service_type, /* Service reference type */ /* (ie "SUNW_fns_calendar"); */ const char *org, /* Org name (ie "ssi"). NULL for default org */ char *buf, /* Buffer to place name in */ const int size) /* Size of value_buf */ { char *tmp_buf; char *type_str; if (libfns_handle == NULL) { return 0; } if (name == NULL) { return -1; } if (org != NULL && *org != '\0') { /* Sanity check for size */ if (strlen(org) + strlen(name) > (size_t)size - 50) { return -1; } /*Construct Helix name from name and organization */ sprintf(buf,"%s:%s:%s:%s:%s:%s", DTFNS_ORG_NAME, org, type, name, DTFNS_SERVICE_NAME, service); } else if (dtfns_isa_helix_name(name)) { /* Helix name. Expand it to point to calendar service */ if (get_helix_service_name(name, service, service_type, &tmp_buf) < 0) { return -1; } buf[size - 1] = '\0'; strncpy(buf, tmp_buf, size - 1); free(tmp_buf); } else { /* Construct Helix name from name */ sprintf(buf,"%s:%s:%s:%s", type, name, DTFNS_SERVICE_NAME, service); } return 1; } /* * Return TRUE if 'name' is an absolute Helix name */ int dtfns_isa_helix_name(const char *name) { int n, len; char **p; for (p = initial_context_names; *p != NULL; p++) { len = strlen(*p); if (strncmp(name, *p, len) == 0) { return TRUE; } } return FALSE; } /* * Get the org name for "myorg" (ie ssi.eng) */ void dtfns_myorg_name(char *buf, int len) { char *__nis_local_root(); static char *myorg_name; char *principal_name; char *host_domain; char *root_domain; char *pd = NULL; char *myorg_p, *root_p; if (myorg_name == NULL) { principal_name = nis_local_principal(); host_domain = nis_local_directory(); root_domain = __nis_local_root(); if (principal_name) { /* Get the domain this principal is in */ pd = nis_domain_of(principal_name); if (pd && *pd == '.') { pd = NULL; } } /* If no domain for the principal, use the one for the host */ myorg_name = strdup(pd ? pd : (host_domain ? host_domain : "")); /* * We want to strip the root domain name off of the * end of the myorg name. Set pointers to the end * of each name */ myorg_p = myorg_name + strlen(myorg_name) - 1; root_p = root_domain + strlen(root_domain) - 1; while (tolower(*myorg_p) == tolower(*root_p)) { if (root_p == root_domain) { /* Matched all of root domain name. Truncate */ if (myorg_p != myorg_name) { *--myorg_p = '\0'; } break; } else if (myorg_p == myorg_name) { break; } --myorg_p; --root_p; } } if (myorg_name != NULL) { buf[len - 1] = '\0'; strncpy(buf, myorg_name, len - 1); } return; } /* * Return the string value bound to an absolute Helix name * * Returns * -1 Error * 0 FNS not available * 1 Success */ int dtfns_lookup_str( const char *name, /* Absolute Helix name */ char *types[], /* Type of data to get */ char *dbuf, /* Buffer to place data value in */ int dsize, /* Size of dbuf */ char *tbuf, /* Buffer to place address type in */ int tsize) /* Size of tbuf */ { NS_Reference_t * ref; const NS_ReferenceAddress_t * addr; void *iter_pos; if (libfns_handle == NULL) { return 0; } /* Get the reference from the name */ if ((ref = dtfns_lookup_ref(name)) == NULL) { return -1; } /* Get the address that matches at least one of the specified types */ if ((addr = dtfns_addr_from_ref(ref, types, &iter_pos)) == NULL) { (*NS_Reference_delete_p)(ref); return -1; } (*NS_Reference_delete_p)(ref); /* Return data bound to that address */ return dtfns_str_from_addr(addr, dbuf, dsize, tbuf, tsize); } /* * * Bind a string to a name. * * name Absolute Helix name to bind string to * * ref_type Reference type. We need this to create * the reference if it does not already exist. * * types Array of address types. This routine looks for * the address that matches at least one of these * types. The first type is used when the new * string is bound. * * new_str String to bind to name * * Returns * -1 Error * 0 FNS not available * 1 Success */ int dtfns_bind_str( const char *name, /* Absolute Helix name */ const char *ref_type, /* Reference type */ char *types[], /* Address type of data to operate on */ const char *new_str /* String to bind to name */ ) { NS_Reference_t *ref = NULL; const NS_ReferenceAddress_t *addr = NULL; NS_ReferenceAddress_t *new_addr = NULL; NS_CompositeName_t *comp_name; NS_ContextStatus_t *status = NULL; NS_Context_t *ctx = NULL; NS_String_t *nstr; void *iter_pos = NULL; char buf[256]; int rcode = -1; if (libfns_handle == NULL) { return 0; } /* Get the reference from the name */ if ((ref = dtfns_lookup_ref(name)) != NULL) { /* * A value is already bound to this name. * Get the address that matches at least one of * the specified types */ addr = dtfns_addr_from_ref(ref, types, &iter_pos); if (addr != NULL) { /* Get string bound to that address */ *buf = '\0'; dtfns_str_from_addr(addr, buf, sizeof(buf), NULL, 0); /* Are we changing the string? */ if (strcmp(buf, new_str) == 0) { /* Bound value is the same as new value */ rcode = 1; goto EXIT; } else { /* Delete old address string */ (*NS_Reference_delete_addr_p)(ref, &iter_pos); } } } else { /* Nothing bound to name. Create an empty reference */ nstr = (*NS_String_from_cstring_p)(ref_type); ref = (*NS_Reference_new_p)(nstr); iter_pos = NULL; } /* Create new address */ if ((new_addr = dtfns_create_str_addr(new_str, types[0])) == NULL) { goto EXIT; } /* Insert new address into reference */ if (dtfns_insert_addr(ref, &iter_pos, new_addr) < 1) { goto EXIT; } /* Bind reference into name space */ if ((ctx = dtfns_get_initial_ctx()) == NULL) { goto EXIT; } status = (*NS_ContextStatus_new_p)(); comp_name = (*NS_CompositeName_from_cstring_p)(name); if ((*NS_Context_bind_p)(ctx, comp_name, ref, 0, status) < 1) { goto EXIT; } rcode = 1; EXIT: /* Clean up and return */ if (new_addr != NULL) (*NS_ReferenceAddress_delete_p)(new_addr); if (ref != NULL) (*NS_Reference_delete_p)(ref); if (status != NULL) (*NS_ContextStatus_delete_p)(status); return rcode; } /* * Return the reference bound to an absolute Helix name * * Returns * NULL Error * NS_Reference_t * for reference */ NS_Reference_t * dtfns_lookup_ref( const char *name)/* Absolute Helix name to lookup */ { NS_Reference_t * ref = NULL; NS_ContextStatus_t * status = NULL; NS_CompositeName_t * comp_name = NULL; NS_Context_t * ctx; if (libfns_handle == NULL) { return NULL; } status = (*NS_ContextStatus_new_p)(); if ((ctx = dtfns_get_initial_ctx()) != NULL) { /* Lookup the Helix name specified by "name" */ comp_name = (*NS_CompositeName_from_cstring_p)(name); ref = (*NS_Context_lookup_p)(ctx, comp_name, status); } (*NS_ContextStatus_delete_p)(status); return ref; } /* * Takes a Helix name and converts it to a full name for a service. * I.e. if service is "calendar": * * name buf * org:ss-eng:user:dipol --> org:ss-eng:user:dipol:service:calendar * org:ss-eng --> org:ss-eng:service:calendar * org:ss-eng:service: --> org:ss-eng:service:calendar * * Returns * -1 Error. buf not set * 0 name already points to the service * buf is a duplicate of name. * 1 name resolved. buf is set. Caller * is responsible for freeing memory. */ static int get_helix_service_name( const char *name, const char *service, const char *service_type, char **buf) { int n; char *tmp_name; NS_Reference_t *ref; NS_String_t *nstr; const char *type; char *p; n = strlen(name); tmp_name = strdup(name); /* Remove trailing : if there is one */ if (tmp_name[n - 1] == ':') { tmp_name[n - 1] = '\0'; n--; } /* Get reference and extract reference type */ if ((ref = dtfns_lookup_ref(tmp_name)) == NULL) { return -1; } nstr = (*NS_Reference_type_p)(ref); type = (*NS_String_cstring_p)(nstr); (*NS_Reference_delete_p)(ref); /* If name is already bound to a calendar service then we are done */ if (strcmp(type, service_type) == 0) { *buf = strdup(name); return 0; } if ((p = strrchr(tmp_name, ':')) != NULL) { p++; } /* * If name is a service context or the "service" null context * then we want to append ":calendar" */ if (strcmp(type, DTFNS_SERVICE_CONTEXT_TYPE) == 0 || (strcmp(type, DTFNS_NULL_CONTEXT_TYPE) == 0 && p != NULL && strcmp(p, DTFNS_SERVICE_NAME) == 0)) { *buf = (char *)malloc(n + strlen(service) + 2); if (*buf == NULL) { return -1; } strcpy(*buf, tmp_name); strcat(*buf, ":"); strcat(*buf, service); return 1; } else { /* Append ":service:calendar" */ *buf = (char *)malloc(n + strlen(DTFNS_SERVICE_NAME) + strlen(service) + 3); sprintf(*buf, "%s:%s:%s", tmp_name, DTFNS_SERVICE_NAME, service); return 1; } } /* * Get an FNS Address from a Reference. * * ref The Reference to get the address from * * types NULL terminated array of one or more type strings. * This routine returns the first address that matches * a type specified in this array. NULL to just * get the first address. * * iter_pos Updated to point after retrieved address. * * Returns * Pointer to the found address * NULL if no address is found * */ const NS_ReferenceAddress_t * dtfns_addr_from_ref( const NS_Reference_t *ref, /* Reference to get addr from */ char *types[], /* Types of addrs to get */ void **iter_pos /* Returned pos where addr was found */ ) { const NS_ReferenceAddress_t *addr; char type[128]; char **p; if (libfns_handle == NULL) { return 0; } addr = (*NS_Reference_first_p)(ref, iter_pos); if (types == NULL) { return addr; } while (addr != NULL) { /* Get the type, and see if it is one we want */ dtfns_str_from_addr(addr, NULL, 0, type, sizeof(type)); for (p = types; *p != NULL && strcmp(*p, type) != 0; *p++) ; if (*p != NULL) { /* Found it! */ break; } else { /* Get next address */ addr = (*NS_Reference_next_p)(ref, iter_pos); } } return addr; } /* * Get the string and type out of an Address * * Returns * -1 Error * 0 FNS not available * 1 Success */ int dtfns_str_from_addr( const NS_ReferenceAddress_t *addr, /* Addr to get string from */ char *dbuf, /* Buf to hold string data */ int dbuf_size, /* Size of dbuf */ char *tbuf, /* Buf to hold string type */ int tbuf_size /* size of tbuf */ ) { XDR xdr; char *s = NULL; NS_String_t *nstr; const char *cs; if (libfns_handle == NULL) { return 0; } if (dbuf != NULL) { /* Convert data from XDR to a string */ xdrmem_create(&xdr, (caddr_t)(*NS_ReferenceAddress_data_p)(addr), (*NS_ReferenceAddress_length_p)(addr), XDR_DECODE); if (xdr_string(&xdr, &s, ~0) == FALSE) { return -1; } dbuf[dbuf_size - 1] = '\0'; strncpy(dbuf, s, dbuf_size - 1); free(s); } if (tbuf != NULL) { tbuf[tbuf_size - 1] = '\0'; nstr = (*NS_ReferenceAddress_type_p)(addr); cs = (*NS_String_cstring_p)(nstr); strncpy(tbuf, cs, tbuf_size - 1); } return 1; } /* * Create an Address of type "type" for the string specified by "data" * * Returns * A new address contianing the specified data * NULL on an error */ NS_ReferenceAddress_t * dtfns_create_str_addr( const char *data, const char *type ) { XDR xdr; u_char buf[1024]; NS_String_t *nstring; if (libfns_handle == NULL) { return NULL; } xdrmem_create(&xdr, (caddr_t)buf, sizeof(buf), XDR_ENCODE); if (xdr_string(&xdr, (char**)&data, ~0) == FALSE) { return NULL; } nstring = (*NS_String_from_cstring_p)(type); return (*NS_ReferenceAddress_new_p)(nstring, xdr_getpos(&xdr), buf); } /* * Add an address to a reference at the location specified by iter_pos. * The address is inserted before iter_pos. * If *iter_pos is NULL then put the address in the first slot. * * Returns * -1 Error * 0 FNS not available * 1 Success */ int dtfns_insert_addr( NS_Reference_t *ref, void **iter_pos, const NS_ReferenceAddress_t *addr ) { if (libfns_handle == NULL) { return 0; } if (*iter_pos == NULL) { if ((*NS_Reference_prepend_addr_p)(ref, addr) < 1) return -1; } else { if ((*NS_Reference_insert_addr_p)(ref, iter_pos, addr) < 1) return -1; } return 1; } /* * Delete the Address at position "iter_pos" from a Reference * * Returns * -1 Error * 0 FNS not available * 1 Success */ int dtfns_delete_addr( NS_Reference_t *ref, void **iter_pos ) { if (libfns_handle == NULL) { return 0; } (*NS_Reference_delete_addr_p)(ref, iter_pos); return 1; } #endif /* FNS */