Merge branch 'develop' into MXS-329

This commit is contained in:
Markus Makela
2015-09-24 17:59:36 +03:00
24 changed files with 1937 additions and 529 deletions

View File

@ -72,20 +72,39 @@
WHERE user.user IS NOT NULL AND user.user <> ''"
#else
# define LOAD_MYSQL_USERS_QUERY "SELECT user, host, password, concat(user,host,password,Select_priv) AS userdata, Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
# define LOAD_MYSQL_USERS_QUERY "SELECT \
user, host, password, concat(user,host,password,Select_priv) AS userdata, \
Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
#endif
#define MYSQL_USERS_COUNT "SELECT COUNT(1) AS nusers FROM mysql.user"
#define MYSQL_USERS_WITH_DB_ORDER " ORDER BY host DESC"
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT user.user AS user,user.host AS host,user.password AS password,concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, user.Select_priv AS anydb,db.db AS db FROM mysql.user LEFT JOIN mysql.db ON user.user=db.user AND user.host=db.host WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT \
user.user AS user, \
user.host AS host, \
user.password AS password, \
concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, \
user.Select_priv AS anydb, \
db.db AS db \
FROM mysql.user LEFT JOIN mysql.db \
ON user.user=db.user AND user.host=db.host \
WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
#define MYSQL_USERS_WITH_DB_COUNT "SELECT COUNT(1) AS nusers_db FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS tbl_count"
#define LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS t1 WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
#define LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * \
FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS t1 \
WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * FROM ( (SELECT COUNT(1) AS ndbs FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, (SELECT GRANTEE,PRIVILEGE_TYPE from INFORMATION_SCHEMA.USER_PRIVILEGES WHERE privilege_type='SHOW DATABASES' AND REPLACE(GRANTEE, \'\\'\',\'\')=CURRENT_USER()) AS tbl2)"
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * \
FROM ( (SELECT COUNT(1) AS ndbs \
FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, \
(SELECT GRANTEE,PRIVILEGE_TYPE from INFORMATION_SCHEMA.USER_PRIVILEGES \
WHERE privilege_type='SHOW DATABASES' AND REPLACE(GRANTEE, \'\\'\',\'\')=CURRENT_USER()) AS tbl2)"
#define ERROR_NO_SHOW_DATABASES "%s: Unable to load database grant information, MaxScale authentication will proceed without including database permissions. To correct this GRANT SHOW DATABASES ON *.* privilege to the user %s."
#define ERROR_NO_SHOW_DATABASES "%s: Unable to load database grant information, \
MaxScale authentication will proceed without including database permissions. \
To correct this GRANT SHOW DATABASES ON *.* privilege to the user %s."
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -1238,7 +1257,7 @@ getUsers(SERVICE *service, USERS *users)
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to get user data from backend database "
"for service [%s]. Missing server information.",
"for service [%s]. Failed to connect to any of the backend databases.",
service->name)));
mysql_close(con);
return -1;
@ -2175,6 +2194,7 @@ int tmp;
free(dbkey);
return NULL;
}
dbkey->resource[tmp] = 0; // NULL Terminate
}
else // NULL is valid, so represent with a length of -1
{
@ -2429,9 +2449,8 @@ bool check_service_permissions(SERVICE* service)
{
if(mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
{
skygw_log_write(LE,"%s: Error: User '%s' is missing SELECT privileges on mysql.db table. MySQL error message: %s",
skygw_log_write(LE,"%s: Warning: User '%s' is missing SELECT privileges on mysql.db table. Database name will be ignored in authentication. MySQL error message: %s",
service->name,user,mysql_error(mysql));
rval = false;
}
else
{

View File

@ -109,7 +109,9 @@ static inline void dcb_write_fake_code(DCB *dcb);
static inline void dcb_write_when_already_queued(DCB *dcb, GWBUF *queue);
static void dcb_log_write_failure(DCB *dcb, GWBUF *queue, int eno);
static inline void dcb_write_tidy_up(DCB *dcb, bool below_water);
static int dcb_write_SSL_error_report (DCB *dcb, int ret);
static void dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno);
int dcb_bytes_readable_SSL (DCB *dcb, int nread);
void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc);
size_t dcb_get_session_id(
DCB *dcb)
@ -956,208 +958,104 @@ int dcb_read(
* @return -1 on error, otherwise the number of read bytes on the last
* iteration of while loop. 0 is returned if no data available.
*/
int dcb_read_SSL(
DCB *dcb,
GWBUF **head)
int dcb_read_SSL(DCB *dcb,
GWBUF **head)
{
GWBUF *buffer = NULL;
int b,pending;
int rc;
int n;
int nread = 0;
int ssl_errno = 0;
CHK_DCB(dcb);
GWBUF *buffer = NULL;
int b, n, nread = 0;
CHK_DCB(dcb);
if (dcb->fd <= 0)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Read failed, dcb is %s.",
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable")));
n = 0;
goto return_n;
}
if (dcb->fd <= 0)
{
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error : Read failed, dcb is %s.",
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable")));
return 0;
}
while (true)
while ((b = dcb_bytes_readable_SSL(dcb, nread)) > 0)
{
dcb->last_read = hkheartbeat;
int bufsize = MIN(b, MAX_BUFFER_SIZE);
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
{
int bufsize;
ssl_errno = 0;
rc = ioctl(dcb->fd, FIONREAD, &b);
pending = SSL_pending(dcb->ssl);
if (rc == -1)
{
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : ioctl FIONREAD for dcb %p in "
"state %s fd %d failed due error %d, %s.",
dcb,
STRDCBSTATE(dcb->state),
dcb->fd,
errno,
strerror_r(errno, errbuf, sizeof(errbuf)))));
n = -1;
goto return_n;
}
/*<
* This is a fatal error which should cause shutdown.
* Todo shutdown if memory allocation fails.
*/
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error : Failed to allocate read buffer "
"for dcb %p fd %d, due %d, %s.",
dcb,
dcb->fd,
errno,
strerror_r(errno, errbuf, sizeof (errbuf)))));
if (b == 0 && pending == 0 && nread == 0)
{
/** Handle closed client socket */
if (dcb_isclient(dcb))
{
char c = 0;
int r = -1;
return -1;
}
/* try to read 1 byte, without consuming the socket buffer */
r = SSL_peek(dcb->ssl, &c, sizeof(char));
if (r <= 0)
{
ssl_errno = SSL_get_error(dcb->ssl,r);
if(ssl_errno != SSL_ERROR_WANT_READ &&
ssl_errno != SSL_ERROR_WANT_WRITE &&
ssl_errno != SSL_ERROR_NONE)
n = -1;
else
n = 0;
goto return_n;
}
}
n = 0;
goto return_n;
}
else if (b == 0 && pending == 0)
{
n = 0;
goto return_n;
}
n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize);
dcb->stats.n_reads++;
if (n <= 0)
{
int ssl_errno = SSL_get_error(dcb->ssl, n);
dcb_log_ssl_read_error(dcb, ssl_errno, n);
if (ssl_errno != SSL_ERROR_WANT_READ &&
ssl_errno != SSL_ERROR_WANT_WRITE &&
ssl_errno != SSL_ERROR_NONE)
{
nread = -1;
gwbuf_free(buffer);
}
return nread;
}
buffer = gwbuf_rtrim(buffer, bufsize - n);
if (buffer)
{
#ifdef SS_DEBUG
else
{
skygw_log_write_flush(LD,"Total: %d Socket: %d Pending: %d",
nread,b,pending);
}
skygw_log_write(LD, "%lu SSL: Truncated buffer from %d to %d bytes. "
"Read %d bytes, %d bytes waiting.\n", pthread_self(),
bufsize, GWBUF_LENGTH(buffer), n, b);
if (GWBUF_LENGTH(buffer) != n)
{
skygw_log_sync_all();
}
ss_info_dassert((buffer->start <= buffer->end), "Buffer start has passed end.");
ss_info_dassert(GWBUF_LENGTH(buffer) == n, "Buffer size not equal to read bytes.");
#endif
nread += n;
dcb->last_read = hkheartbeat;
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
"%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s "
"fd %d.",
pthread_self(),
n,
dcb,
STRDCBSTATE(dcb->state),
dcb->fd)));
bufsize = MIN(b, MAX_BUFFER_SIZE);
/*< Append read data to the gwbuf */
*head = gwbuf_append(*head, buffer);
}
}
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
{
/*<
* This is a fatal error which should cause shutdown.
* Todo shutdown if memory allocation fails.
*/
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Failed to allocate read buffer "
"for dcb %p fd %d, due %d, %s.",
dcb,
dcb->fd,
errno,
strerror_r(errno, errbuf, sizeof(errbuf)))));
ss_dassert(gwbuf_length(*head) == nread);
LOGIF(LD, skygw_log_write(LD, "%lu Read a total of %d bytes from dcb %p in state %s fd %d.",
pthread_self(),
nread,
dcb,
STRDCBSTATE(dcb->state),
dcb->fd));
n = -1;
goto return_n;
}
n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize);
dcb->stats.n_reads++;
if (n < 0)
{
char errbuf[200];
ssl_errno = SSL_get_error(dcb->ssl,n);
#ifdef SS_DEBUG
if(ssl_errno == SSL_ERROR_SSL ||
ssl_errno == SSL_ERROR_SYSCALL)
{
int eno;
while((eno = ERR_get_error()) != 0)
{
ERR_error_string_n(eno,errbuf,200);
skygw_log_write(LE,
"%s",
errbuf);
}
}
#endif
if(ssl_errno == SSL_ERROR_WANT_READ ||
ssl_errno == SSL_ERROR_WANT_WRITE ||
ssl_errno == SSL_ERROR_NONE)
{
n = 0;
}
else
{
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Read failed, dcb %p in state "
"%s fd %d, SSL error %d: %s.",
dcb,
STRDCBSTATE(dcb->state),
dcb->fd,
ssl_errno,
strerror_r(errno, errbuf, sizeof(errbuf)))));
if(ssl_errno == SSL_ERROR_SSL ||
ssl_errno == SSL_ERROR_SYSCALL)
{
while((ssl_errno = ERR_get_error()) != 0)
{
ERR_error_string_n(ssl_errno,errbuf,200);
skygw_log_write(LE,
"%s",
errbuf);
}
}
}
n = -1;
gwbuf_free(buffer);
goto return_n;
}
else if(n == 0)
{
gwbuf_free(buffer);
goto return_n;
}
buffer = gwbuf_rtrim(buffer,bufsize - n);
if(buffer == NULL)
{
goto return_n;
}
#ifdef SS_DEBUG
skygw_log_write(LD,"%lu SSL: Truncated buffer from %d to %d bytes. "
"Read %d bytes, %d bytes waiting.\n",pthread_self(),
bufsize,GWBUF_LENGTH(buffer),n,b);
if(GWBUF_LENGTH(buffer) != n){
skygw_log_sync_all();
}
ss_info_dassert((buffer->start <= buffer->end),"Buffer start has passed end.");
ss_info_dassert(GWBUF_LENGTH(buffer) == n,"Buffer size not equal to read bytes.");
#endif
nread += n;
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s "
"fd %d.",
pthread_self(),
n,
dcb,
STRDCBSTATE(dcb->state),
dcb->fd)));
/*< Append read data to the gwbuf */
*head = gwbuf_append(*head, buffer);
} /*< while (true) */
return_n:
return nread;
return nread;
}
/**
@ -1500,21 +1398,28 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
#if defined(FAKE_CODE)
dcb_write_fake_code(dcb);
#endif /* FAKE_CODE */
do
{
do
{
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(queue), GWBUF_LENGTH(queue));
dcb->stats.n_writes++;
dcb->stats.n_writes++;
if (w <= 0)
{
int ssl_errno = dcb_write_SSL_error_report (dcb, w);
if(ssl_errno != SSL_ERROR_WANT_WRITE)
if (w <= 0)
{
int ssl_errno = SSL_get_error(dcb->ssl, w);
dcb_write_SSL_error_report(dcb, w, ssl_errno);
if (ssl_errno != SSL_ERROR_WANT_WRITE)
{
atomic_add(&dcb->writeqlen, gwbuf_length(queue));
dcb->stats.n_buffered++;
dcb_write_tidy_up(dcb, below_water);
return 1;
}
#ifdef SS_DEBUG
else
{
skygw_log_write(LD, "SSL error: SSL_ERROR_WANT_WRITE, retrying SSL_write...");
}
#endif
}
} while(w <= 0);
@ -1548,14 +1453,12 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
*
* @param dcb The DCB of the client
* @param ret The SSL operation return code
* @return The final SSL error number
* @param ssl_errno The SSL error code
*/
static int
dcb_write_SSL_error_report (DCB *dcb, int ret)
static void
dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno)
{
int ssl_errno;
char errbuf[STRERROR_BUFLEN];
ssl_errno = SSL_get_error(dcb->ssl,ret);
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
{
@ -1634,7 +1537,6 @@ dcb_write_SSL_error_report (DCB *dcb, int ret)
} while((ssl_errno = ERR_get_error()) != 0);
}
}
return SSL_ERROR_NONE;
}
/**
@ -3209,3 +3111,104 @@ char *name = NULL;
}
return name;
}
/**
* Check how much data is readable from an SSL enabled DCB.
* @param dcb DCB to check
* @param nread Number of bytes we have already read
* @return Number of bytes readable or -1 on error
*/
int dcb_bytes_readable_SSL(DCB *dcb, int nread)
{
int rval = 0;
int nbytes;
int rc = ioctl(dcb->fd, FIONREAD, &nbytes);
if (rc == -1)
{
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error : ioctl FIONREAD for dcb %p in "
"state %s fd %d failed due error %d, %s.",
dcb,
STRDCBSTATE(dcb->state),
dcb->fd,
errno,
strerror_r(errno, errbuf, sizeof (errbuf)))));
rval = -1;
}
else
{
int pending = SSL_pending(dcb->ssl);
rval = nbytes + pending;
if (rval == 0 && nread == 0)
{
/** Handle closed client socket */
if (dcb_isclient(dcb))
{
char c = 0;
int r = -1;
/* try to read 1 byte, without consuming the socket buffer */
r = SSL_peek(dcb->ssl, &c, sizeof (char));
if (r <= 0)
{
int ssl_errno = SSL_get_error(dcb->ssl, r);
if (ssl_errno != SSL_ERROR_WANT_READ &&
ssl_errno != SSL_ERROR_WANT_WRITE &&
ssl_errno != SSL_ERROR_NONE)
rval = -1;
}
}
}
#ifdef SS_DEBUG
else if (nbytes != 0 || pending != 0)
{
skygw_log_write_flush(LD, "Total: %d Socket: %d Pending: %d",
nread, nbytes, pending);
}
else
{
skygw_log_write(LD, "Tried to read from socket, no data left. %d bytes read in total.", nread);
}
#endif
}
return rval;
}
/**
* Log SSL read error messages
* @param dcb DCB from which the SSL_read was attempted
* @param ssl_errno SSL error number
* @param rc Return value of SSL_read
*/
void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc)
{
if (ssl_errno != SSL_ERROR_WANT_READ &&
ssl_errno != SSL_ERROR_WANT_WRITE &&
ssl_errno != SSL_ERROR_NONE)
{
char errbuf[STRERROR_BUFLEN];
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"Error : Read failed, dcb %p in state "
"%s fd %d, SSL error %d: %s.",
dcb,
STRDCBSTATE(dcb->state),
dcb->fd,
ssl_errno,
strerror_r(errno, errbuf, sizeof (errbuf)))));
if (ssl_errno == SSL_ERROR_SSL ||
ssl_errno == SSL_ERROR_SYSCALL)
{
while ((ssl_errno = ERR_get_error()) != 0)
{
ERR_error_string_n(ssl_errno, errbuf, STRERROR_BUFLEN);
skygw_log_write(LE,
"%s",
errbuf);
}
}
}
}

View File

@ -114,6 +114,7 @@ EXTERNCMD* externcmd_allocate(char* argstr)
externcmd_free(cmd);
return NULL;
}
skygw_log_write(LT, "Executing script %s.", cmd->parameters[0]);
}
return cmd;
}

View File

@ -181,6 +181,7 @@ static struct option long_options[] = {
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, '?'},
{"version-full", no_argument, 0, 'V'},
{"log_augmentation", required_argument, 0, 'G'},
{0, 0, 0, 0}
};
static int cnf_preparser(void* data, const char* section, const char* name, const char* value);
@ -197,6 +198,7 @@ static int ntfw_cb(const char*, const struct stat*, int, struct FTW*);
static bool file_is_readable(char* absolute_pathname);
static bool file_is_writable(char* absolute_pathname);
bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr);
static void set_log_augmentation(const char* value);
static void usage(void);
static char* get_expanded_pathname(
char** abs_path,
@ -216,6 +218,7 @@ static bool resolve_maxscale_conf_fname(
static char* check_dir_access(char* dirname,bool,bool);
static int set_user();
bool pid_file_exists();
void write_child_exit_code(int fd, int code);
/** SSL multi-threading functions and structures */
static SPINLOCK* ssl_locks;
@ -1071,6 +1074,9 @@ int main(int argc, char **argv)
int n_services;
int eno = 0; /*< local variable for errno */
int opt;
int daemon_pipe[2];
bool parent_process;
int child_status;
void** threads = NULL; /*< thread list */
char mysql_home[PATH_MAX+1];
char datadir_arg[10+PATH_MAX+1]; /*< '--datadir=' + PATH_MAX */
@ -1128,7 +1134,7 @@ int main(int argc, char **argv)
}
}
while ((opt = getopt_long(argc, argv, "dc:f:l:vVs:S:?L:D:C:B:U:A:P:",
while ((opt = getopt_long(argc, argv, "dc:f:l:vVs:S:?L:D:C:B:U:A:P:G:",
long_options, &option_index)) != -1)
{
bool succp = true;
@ -1291,6 +1297,9 @@ int main(int argc, char **argv)
succp = false;
}
break;
case 'G':
set_log_augmentation(optarg);
break;
case '?':
usage();
rc = EXIT_SUCCESS;
@ -1321,6 +1330,13 @@ int main(int argc, char **argv)
}
else
{
if(pipe(daemon_pipe) == -1)
{
fprintf(stderr,"Error: Failed to create pipe for inter-process communication: %d %s",errno,strerror(errno));
rc = MAXSCALE_INTERNALERROR;
goto return_main;
}
/*<
* Maxscale must be daemonized before opening files, initializing
* embedded MariaDB and in general, as early as possible.
@ -1453,7 +1469,37 @@ int main(int argc, char **argv)
rc = MAXSCALE_INTERNALERROR;
goto return_main;
}
gw_daemonize();
/** Daemonize the process and wait for the child process to notify
* the parent process of its exit status. */
parent_process = gw_daemonize();
if(parent_process)
{
close(daemon_pipe[1]);
int nread = read(daemon_pipe[0],(void*)&child_status,sizeof(int));
close(daemon_pipe[0]);
if(nread == -1)
{
char* logerr = "Failed to read data from child process pipe.";
print_log_n_stderr(true, true, logerr, logerr, errno);
exit(MAXSCALE_INTERNALERROR);
}
else if(nread == 0)
{
/** Child process has exited or closed write pipe */
char* logerr = "No data read from child process pipe.";
print_log_n_stderr(true, true, logerr, logerr, 0);
exit(MAXSCALE_INTERNALERROR);
}
exit(child_status);
}
/** This is the child process and we can close the read end of
* the pipe. */
close(daemon_pipe[0]);
}
/*<
* Set signal handlers for SIGHUP, SIGTERM, SIGINT and critical signals like SIGSEGV.
@ -1602,7 +1648,6 @@ int main(int argc, char **argv)
if (!resolve_maxscale_conf_fname(&cnf_file_path, pathbuf, cnf_file_arg))
{
ss_dassert(cnf_file_path == NULL);
rc = MAXSCALE_BADCONFIG;
goto return_main;
}
@ -1857,7 +1902,7 @@ int main(int argc, char **argv)
}
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"MariaDB Corporation MaxScale %s (C) MariaDB Corporation Ab 2013-2014",
"MariaDB Corporation MaxScale %s (C) MariaDB Corporation Ab 2013-2015",
MAXSCALE_VERSION)));
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
@ -1950,6 +1995,13 @@ int main(int argc, char **argv)
CRYPTO_set_id_callback(pthread_self);
#endif
/**
* Successful start, notify the parent process that it can exit.
*/
ss_dassert(rc == MAXSCALE_SHUTDOWN);
if(daemon_mode)
write_child_exit_code(daemon_pipe[1], rc);
MaxScaleStarted = time(0);
/*<
* Serve clients.
@ -1988,6 +2040,13 @@ int main(int argc, char **argv)
unlink_pidfile();
return_main:
if(daemon_mode && rc != MAXSCALE_SHUTDOWN)
{
/** Notify the parent process that an error has occurred */
write_child_exit_code(daemon_pipe[1], rc);
}
if (threads)
free(threads);
if (cnf_file_path)
@ -2312,6 +2371,21 @@ bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr)
return rval;
}
void set_log_augmentation(const char* value)
{
// Command line arguments are handled first, thus command line argument
// has priority.
static bool augmentation_set = false;
if (!augmentation_set)
{
skygw_log_set_augmentation(atoi(value));
augmentation_set = true;
}
}
/**
* Pre-parse the MaxScale.cnf for config, log and module directories.
* @param data Parameter passed by inih
@ -2423,6 +2497,10 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons
{
cnf->maxlog = config_truth_value((char*)value);
}
else if(strcmp(name, "log_augmentation") == 0)
{
set_log_augmentation(value);
}
}
return 1;
@ -2481,3 +2559,15 @@ static int set_user(char* user)
return rval;
}
/**
* Write the exit status of the child process to the parent process.
* @param fd File descriptor to write to
* @param code Exit status of the child process
*/
void write_child_exit_code(int fd, int code)
{
/** Notify the parent process that an error has occurred */
write(fd, &code, sizeof (int));
close(fd);
}

View File

@ -141,7 +141,7 @@ setipaddress(struct in_addr *a, char *p) {
* Daemonize the process by forking and putting the process into the
* background.
*/
void gw_daemonize(void) {
bool gw_daemonize(void) {
pid_t pid;
pid = fork();
@ -154,7 +154,7 @@ void gw_daemonize(void) {
if (pid != 0) {
/* exit from main */
exit(0);
return true;
}
if (setsid() < 0) {
@ -162,6 +162,7 @@ void gw_daemonize(void) {
fprintf(stderr, "setsid() error %s\n", strerror_r(errno, errbuf, sizeof(errbuf)));
exit(1);
}
return false;
}
/**