/* * plugin_modify_key_value * A wrapper function for invoking the plugin dependency set/del call * for a changed a key value. * The routine logs on debug. * It also checks whether an error was properly registered using clicon_err(). * Arguments: * db: The database which contains the key value, most relevant in a set operation * but may possibly in some cases be important in delete operations, although * I cannot think of any,.. * key: The name of the key in the database above. * op: Either set or delete * dep: plugin dependency information. Contains function and argument pointers. * * Returns: * 0: OK * -1: An error occured in the plugin commit function. It is assumed that * clicon_err() has been called there. Here, we interpret the clicon_err * as a 'commit' error and does not handle it fatally. */ static int plugin_modify_key_value(clicon_handle h, char *db, char *key, enum trans_cb_type type, lv_op_t op, dbdep_t *dp) { int retval = -1; clicon_debug(2, "commit diff %c%s", (op==LV_SET)?'+':'-', key); clicon_err_reset(); if (dp->dp_callback(h, db, type, op, key, dp->dp_arg) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_err(OE_DB, 0, "Unknown error: %c%s: plugin does not make clicon_err call on error", (op==LV_SET)?'+':'-', key); goto done; } retval = 0; done: return retval; }
/*! Load a dynamic plugin object and call its init-function * @param[in] h Clicon handle * @param[in] file Which plugin to load * @param[in] function Which function symbol to load and call * @param[in] dlflags See man(3) dlopen * @param[out] cpp Clixon plugin structure (if retval is 1) * @retval 1 OK * @retval 0 Failed load, log, skip and continue with other plugins * @retval -1 Error * @see clixon_plugins_load Load all plugins */ static int plugin_load_one(clicon_handle h, char *file, char *function, int dlflags, clixon_plugin **cpp) { int retval = -1; char *error; void *handle = NULL; plginit2_t *initfn; clixon_plugin_api *api = NULL; clixon_plugin *cp = NULL; char *name; char *p; clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function); dlerror(); /* Clear any existing error */ if ((handle = dlopen(file, dlflags)) == NULL) { error = (char*)dlerror(); clicon_err(OE_PLUGIN, errno, "dlopen: %s", error ? error : "Unknown error"); goto done; } /* call plugin_init() if defined, eg CLIXON_PLUGIN_INIT or CLIXON_BACKEND_INIT */ if ((initfn = dlsym(handle, function)) == NULL){ clicon_err(OE_PLUGIN, errno, "Failed to find %s when loading clixon plugin %s", CLIXON_PLUGIN_INIT, file); goto done; } if ((error = (char*)dlerror()) != NULL) { clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error); goto done; } clicon_err_reset(); if ((api = initfn(h)) == NULL) { if (!clicon_errno){ /* if clicon_err() is not called then log and continue */ clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file); retval = 0; goto done; } else{ clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file); goto done; } } /* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */ if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); goto done; } memset(cp, 0, sizeof(struct clixon_plugin)); cp->cp_handle = handle; /* Extract string after last '/' in filename, if any */ name = strrchr(file, '/') ? strrchr(file, '/')+1 : file; /* strip extension, eg .so from name */ if ((p=strrchr(name, '.')) != NULL) *p = '\0'; /* Copy name to struct */ memcpy(cp->cp_name, name, strlen(name)+1); snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s", (int)strlen(name), name); cp->cp_api = *api; clicon_debug(1, "%s", __FUNCTION__); if (cp){ *cpp = cp; cp = NULL; } retval = 1; done: if (retval != 1 && handle) dlclose(handle); if (cp) free(cp); return retval; }