From 1e363b9ad74d024e773c53ee1a67464e0c614c20 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Thu, 11 Feb 2016 16:13:22 +0200 Subject: [PATCH] Figure out path of plugin process executable. The plugin process executable is assumed to be installed in the same directory as the maxscale executable. --- query_classifier/qc_pp/qc_pp.c | 236 +++++++++++++++++++++++++++------ 1 file changed, 196 insertions(+), 40 deletions(-) diff --git a/query_classifier/qc_pp/qc_pp.c b/query_classifier/qc_pp/qc_pp.c index 2fa13ab45..106955a73 100644 --- a/query_classifier/qc_pp/qc_pp.c +++ b/query_classifier/qc_pp/qc_pp.c @@ -35,28 +35,169 @@ #define QC_TRACE() #endif -static QUERY_CLASSIFIER* classifier; -static const char qc_mysqlembedded[] = "qc_mysqlembedded"; +static const char QC_MYSQLEMBEDDED[] = "qc_mysqlembedded"; // The qc plugin we'll temporarily use. +static const char MAXPP[] = "maxpp"; // The name of the plugin process executable. - -static bool qc_pp_init(void) +static struct pp_self { - QC_TRACE(); - ss_dassert(!classifier); + QUERY_CLASSIFIER* classifier; // The classifier. + char classifier_name[PATH_MAX]; // The name of the classifier. + pid_t pp_pid; // The pid of the plugin process. + char pp_path[PATH_MAX]; // The path of the plugin process. +} *self = 0; - bool success = false; - void* module = load_module(qc_mysqlembedded, MODULE_QUERY_CLASSIFIER); + +static QUERY_CLASSIFIER* load_and_init_classifier(const char* name) +{ + QUERY_CLASSIFIER* classifier = NULL; + void* module = load_module(name, MODULE_QUERY_CLASSIFIER); if (module) { classifier = (QUERY_CLASSIFIER*) module; - MXS_NOTICE("%s loaded.", qc_mysqlembedded); - success = classifier->qc_init(); + bool success = classifier->qc_init(); + + if (success) + { + MXS_NOTICE("%s loaded and initialized.", name); + } + else + { + MXS_ERROR("Could not initialize %s.", name); + unload_module(name); + classifier = NULL; + } } else { - MXS_ERROR("Could not load %s.", qc_mysqlembedded); + MXS_ERROR("Could not load %s.", name); + } + + return classifier; +} + +static void end_and_unload_classifier(QUERY_CLASSIFIER* classifier, const char* name) +{ + classifier->qc_end(); + unload_module(name); +} + +static bool resolve_pp_path(char* path, int size) +{ + bool success = false; + ssize_t sz = readlink("/proc/self/exe", path, size); + + if (sz >= 0) + { + if (sz == size) + { + MXS_ERROR("The full path of the current executable does not fit in a " + "buffer of %d bytes.", size); + } + else + { + char* s = path + sz; + + // Find the last '/'. + while ((*s != '/') && (s != path)) + { + --s; + --sz; + } + + if (*s == '/') + { + ++s; + ++sz; + } + + *s = 0; + + int required_size = sz + sizeof(MAXPP) + 1; + + if (required_size + 1 <= size) + { + strcat(path, MAXPP); + + MXS_NOTICE("Path of plugin process executable: %s", path); + success = true; + } + else + { + MXS_ERROR("The full path of the plugin process executable does " + "not fit into a buffer of %d bytes. ", size); + } + } + } + else + { + MXS_ERROR("Could not establish location of current process."); + } + + return success; +} + +static bool is_executable(const char* path) +{ + return access(path, X_OK) == 0; +} + +static bool qc_pp_init(void) +{ + QC_TRACE(); + ss_dassert(!self); + + bool success = false; + + self = malloc(sizeof(*self)); + + if (self) + { + memset(self, 0, sizeof(*self)); + + const char* classifier_name = QC_MYSQLEMBEDDED; + QUERY_CLASSIFIER* classifier = load_and_init_classifier(classifier_name); + + if (classifier) + { + char pp_path[PATH_MAX]; + + if (resolve_pp_path(pp_path, sizeof(pp_path))) + { + if (is_executable(pp_path)) + { + self->classifier = classifier; + strcpy(self->classifier_name, classifier_name); + strcpy(self->pp_path, pp_path); + success = true; + } + else + { + MXS_ERROR("%s does not exist or is not an executable.", pp_path); + } + } + else + { + MXS_ERROR("Could not resolve the path of the plugin process executable. " + "Plugin process will not be launched."); + } + + if (!success) + { + end_and_unload_classifier(classifier, classifier_name); + } + } + + if (!success) + { + free(self); + self = NULL; + } + } + else + { + MXS_ERROR("Out of memory."); } return success; @@ -65,114 +206,129 @@ static bool qc_pp_init(void) static void qc_pp_end(void) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - classifier->qc_end(); - classifier = NULL; + end_and_unload_classifier(self->classifier, self->classifier_name); + free(self); + self = NULL; } static bool qc_pp_thread_init(void) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_thread_init(); + return self->classifier->qc_thread_init(); } static void qc_pp_thread_end(void) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_thread_end(); + return self->classifier->qc_thread_end(); } static qc_query_type_t qc_pp_get_type(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_type(query); + return self->classifier->qc_get_type(query); } static qc_query_op_t qc_pp_get_operation(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_operation(query); + return self->classifier->qc_get_operation(query); } static char* qc_pp_get_created_table_name(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_created_table_name(query); + return self->classifier->qc_get_created_table_name(query); } static bool qc_pp_is_drop_table_query(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_is_drop_table_query(query); + return self->classifier->qc_is_drop_table_query(query); } static bool qc_pp_is_real_query(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_is_real_query(query); + return self->classifier->qc_is_real_query(query); } static char** qc_pp_get_table_names(GWBUF* query, int* tblsize, bool fullnames) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_table_names(query, tblsize, fullnames); + return self->classifier->qc_get_table_names(query, tblsize, fullnames); } static char* qc_pp_get_canonical(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_canonical(query); + return self->classifier->qc_get_canonical(query); } static bool qc_pp_query_has_clause(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_query_has_clause(query); + return self->classifier->qc_query_has_clause(query); } static char* qc_pp_get_qtype_str(qc_query_type_t qtype) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_qtype_str(qtype); + return self->classifier->qc_get_qtype_str(qtype); } static char* qc_pp_get_affected_fields(GWBUF* query) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_affected_fields(query); + return self->classifier->qc_get_affected_fields(query); } static char** qc_pp_get_database_names(GWBUF* query, int* sizep) { QC_TRACE(); - ss_dassert(classifier); + ss_dassert(self); + ss_dassert(self->classifier); - return classifier->qc_get_database_names(query, sizep); + return self->classifier->qc_get_database_names(query, sizep); } /**