From 18526c28f6924d32b45e77b804f98647100b5d6b Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Thu, 25 Feb 2016 10:43:16 +0200 Subject: [PATCH] MXS-589: Separated persistent and temporary data directories Both the passwords and temporary files of the embedded library were stored in the same directory. Now the directories are separated and the embedded library uses the temporary directory. The datadir cleanup also now only cleans up the temporary data directory. --- .../qc_mysqlembedded/qc_mysqlembedded.cc | 61 +++-------- server/core/gateway.c | 101 +++++++++++++----- server/core/gwdirs.c | 24 ++++- server/include/gwdirs.h.in | 7 +- 4 files changed, 117 insertions(+), 76 deletions(-) diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index a15d5c298..a8cdb9727 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -1812,33 +1812,6 @@ char datadir_arg[OPTIONS_DATADIR_SIZE]; char language_arg[OPTIONS_LANGUAGE_SIZE]; -bool create_datadir(const char* base, char* datadir) -{ - bool created = false; - - if (snprintf(datadir, PATH_MAX, "%s/data%d", base, getpid()) < PATH_MAX) - { - int rc = mkdir(datadir, 0777); - - if ((rc == 0) || (errno == EEXIST)) - { - created = true; - } - else - { - char errbuf[STRERROR_BUFLEN]; - fprintf(stderr, "MaxScale: error: Cannot create data directory '%s': %d %s\n", - datadir, errno, strerror_r(errno, errbuf, sizeof(errbuf))); - } - } - else - { - fprintf(stderr, "MaxScale: error: Too long data directory: %s/data%d.", base, getpid()); - } - - return created; -} - void configure_options(const char* datadir, const char* langdir) { int rv; @@ -1861,7 +1834,6 @@ void configure_options(const char* datadir, const char* langdir) bool qc_init(void) { bool inited = false; - char datadir[PATH_MAX]; if (strlen(get_langdir()) >= PATH_MAX) { @@ -1869,25 +1841,22 @@ bool qc_init(void) } else { - if (create_datadir(get_datadir(), datadir)) + configure_options(get_process_datadir(), get_langdir()); + + int argc = N_OPTIONS; + char** argv = const_cast(server_options); + char** groups = const_cast(server_groups); + + int rc = mysql_library_init(argc, argv, groups); + + if (rc != 0) { - configure_options(datadir, get_langdir()); - - int argc = N_OPTIONS; - char** argv = const_cast(server_options); - char** groups = const_cast(server_groups); - - int rc = mysql_library_init(argc, argv, groups); - - if (rc != 0) - { - MXS_ERROR("mysql_library_init() failed. Error code: %d", rc); - } - else - { - MXS_NOTICE("Query classifier initialized."); - inited = true; - } + MXS_ERROR("mysql_library_init() failed. Error code: %d", rc); + } + else + { + MXS_NOTICE("Query classifier initialized."); + inited = true; } } diff --git a/server/core/gateway.c b/server/core/gateway.c index e0d11c71f..5c4192275 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -439,7 +439,54 @@ static int signal_set(int sig, void (*handler)(int)) return rc; } +/** + * @brief Create the data directory for this process + * + * This will prevent conflicts when multiple MaxScale instances are run on the + * same machine. + * @param base Base datadir path + * @param datadir The result where the process specific datadir is stored + * @return True if creation was successful and false on error + */ +static bool create_datadir(const char* base, char* datadir) +{ + bool created = false; + int len = 0; + if ((len = snprintf(datadir, PATH_MAX, "%s", base)) < PATH_MAX && + (mkdir(datadir, 0777) == 0 || errno == EEXIST)) + { + if ((len = snprintf(datadir, PATH_MAX, "%s/data%d", base, getpid())) < PATH_MAX) + { + if ((mkdir(datadir, 0777) == 0) || (errno == EEXIST)) + { + created = true; + } + else + { + char errbuf[STRERROR_BUFLEN]; + MXS_ERROR("Cannot create data directory '%s': %d %s\n", + datadir, errno, strerror_r(errno, errbuf, sizeof(errbuf))); + } + } + } + else + { + if (len < PATH_MAX) + { + char errbuf[STRERROR_BUFLEN]; + fprintf(stderr, "Error: Cannot create data directory '%s': %d %s\n", + datadir, errno, strerror_r(errno, errbuf, sizeof(errbuf))); + } + else + { + MXS_ERROR("Data directory pathname exceeds the maximum allowed pathname " + "length: %s/data%d.", base, getpid()); + } + } + + return created; +} /** * Cleanup the temporary data directory we created for the gateway @@ -456,23 +503,28 @@ int ntfw_cb(const char* filename, int eno = errno; errno = 0; char errbuf[STRERROR_BUFLEN]; - MXS_ERROR("Failed to remove the data directory %s of " - "MaxScale due to %d, %s.", - datadir, - eno, - strerror_r(eno, errbuf, sizeof(errbuf))); + MXS_ERROR("Failed to remove the data directory %s of MaxScale due to %d, %s.", + datadir, eno, strerror_r(eno, errbuf, sizeof(errbuf))); } return rc; } -void datadir_cleanup() +/** + * @brief Clean up the data directory + * + * This removes the process specific datadir which is currently only used by + * the embedded library. In the future this directory could contain other + * temporary files and relocating this to to, for example, /tmp/ could make sense. + */ +void cleanup_process_datadir() { int depth = 1; int flags = FTW_CHDIR|FTW_DEPTH|FTW_MOUNT; + const char *proc_datadir = get_process_datadir(); - if (datadir[0] != 0 && access(datadir, F_OK) == 0) + if (strcmp(proc_datadir, get_datadir()) != 0 && access(proc_datadir, F_OK) == 0) { - nftw(datadir, ntfw_cb, depth, flags); + nftw(proc_datadir, ntfw_cb, depth, flags); } } @@ -1235,7 +1287,7 @@ int main(int argc, char **argv) ssize_t log_flush_timeout_ms = 0; sigset_t sigpipe_mask; sigset_t saved_mask; - void (*exitfunp[4])(void) = { mxs_log_finish, datadir_cleanup, write_footer, NULL }; + void (*exitfunp[4])(void) = { mxs_log_finish, cleanup_process_datadir, write_footer, NULL }; *syslog_enabled = 1; *maxlog_enabled = 1; @@ -1718,23 +1770,20 @@ int main(int argc, char **argv) } /* - * Set a data directory for the mysqld library, we use - * a unique directory name to avoid clauses if multiple - * instances of the gateway are being run on the same - * machine. + * Set the data directory for the mysqld library. We use + * a unique directory name to avoid conflicts if multiple + * instances of MaxScale are being run on the same machine. */ - - snprintf(datadir, PATH_MAX, "%s", get_datadir()); - datadir[PATH_MAX] = '\0'; - if (mkdir(datadir, 0777) != 0){ - - if (errno != EEXIST){ - char errbuf[STRERROR_BUFLEN]; - fprintf(stderr, - "Error: Cannot create data directory '%s': %d %s\n", - datadir, errno, strerror_r(errno, errbuf, sizeof(errbuf))); - goto return_main; - } + if (create_datadir(get_datadir(), datadir)) + { + set_process_datadir(datadir); + } + else + { + char errbuf[STRERROR_BUFLEN]; + MXS_ERROR("Cannot create data directory '%s': %d %s\n", + datadir, errno, strerror_r(errno, errbuf, sizeof(errbuf))); + goto return_main; } if (!daemon_mode) @@ -1946,7 +1995,7 @@ int main(int argc, char **argv) qc_end(); utils_end(); - datadir_cleanup(); + cleanup_process_datadir(); MXS_NOTICE("MaxScale shutdown completed."); unload_all_modules(); diff --git a/server/core/gwdirs.c b/server/core/gwdirs.c index 970ec603f..9b28ccc73 100644 --- a/server/core/gwdirs.c +++ b/server/core/gwdirs.c @@ -85,6 +85,17 @@ void set_datadir(char* param) maxscaledatadir = param; } +/** + * Set the data directory + * @param str Path to directory + */ +void set_process_datadir(char* param) +{ + free(processdatadir); + clean_up_pathname(param); + processdatadir = param; +} + /** * Set the library directory. Modules will be loaded from here. * @param str Path to directory @@ -127,14 +138,23 @@ char* get_cachedir() } /** - * Get the service cache directory - * @return The path to the cache directory + * Get the MaxScale data directory + * @return The path to the data directory */ char* get_datadir() { return maxscaledatadir ? maxscaledatadir : (char*) default_datadir; } +/** + * Get the process specific data directory + * @return The path to the process specific directory + */ +char* get_process_datadir() +{ + return processdatadir ? processdatadir : (char*) default_datadir; +} + /** * Get the configuration file directory * @return The path to the configuration file directory diff --git a/server/include/gwdirs.h.in b/server/include/gwdirs.h.in index 440cd56b3..61a624790 100644 --- a/server/include/gwdirs.h.in +++ b/server/include/gwdirs.h.in @@ -35,7 +35,7 @@ static const char* default_configdir = "/etc"; * uses /run for PID files.*/ static const char* default_piddir = "@MAXSCALE_VARDIR@/run/maxscale"; static const char* default_logdir = "@MAXSCALE_VARDIR@/log/maxscale"; -static const char* default_datadir = "@MAXSCALE_VARDIR@/lib/maxscale/data"; +static const char* default_datadir = "@MAXSCALE_VARDIR@/lib/maxscale"; static const char* default_libdir = "@CMAKE_INSTALL_PREFIX@/@MAXSCALE_LIBDIR@"; static const char* default_cachedir = "@MAXSCALE_VARDIR@/cache/maxscale"; static const char* default_langdir = "@MAXSCALE_VARDIR@/lib/maxscale"; @@ -45,13 +45,15 @@ static char* configdir = NULL; static char* logdir = NULL; static char* libdir = NULL; static char* cachedir = NULL; -static char* maxscaledatadir = NULL; +static char* maxscaledatadir = NULL; /*< The data directory */ +static char* processdatadir = NULL; /*< Process specific data directory */ static char* langdir = NULL; static char* piddir = NULL; static char* execdir = NULL; void set_libdir(char* param); void set_datadir(char* param); +void set_process_datadir(char* param); void set_cachedir(char* param); void set_configdir(char* param); void set_logdir(char* param); @@ -60,6 +62,7 @@ void set_piddir(char* param); void set_execdir(char* param); char* get_libdir(); char* get_datadir(); +char* get_process_datadir(); char* get_cachedir(); char* get_configdir(); char* get_piddir();