973b983 Merge branch 'release-2.0.0' into develop 255dd23 Make spinlock functions take const argument 6e23bab Fix bitmask reallocation 338c189 Rename and clean up slavelag filter 3ea8f28 Fix possible NULL pointer dereference bfe6738 MXS-830: Add module information to logged messages 1fad962 Fix strncat usage d38997a Adjust log throttling policy 0be4e4b Add hashtable_item_strcasecmp 726100e Take hashtable convenience functions into use 5e7744a Fix typo in maxadmin.md c5778c8 Merge branch 'release-2.0.0' into develop b5762af Move from tmpnam to mkstemp d6f2c71 Add convenience functions to hashtable 359058a MXS-825: Add support for --execdir 636347c Enable runtime reconfiguration of log throttling ef9fba9 Improve log throttling documentation aef917a Implement log throttling e3a5349 Remove shardrouter.c 8051e80 Remove custom qc_sqlite allocation functions fd34d60 Initial implementation of the learning firewall a8752a8 Removed "filestem option" from example 1ef2519 Removed "filestem option" from example 0815cc8 Cleanup spinlock.h ab4dc99 Clean up hashtable.h ef2c078 Add prototypes for hashtable copy and free functions fb5cfaf Add 'log_throttling' configuration entry 300d823 Add proper prototypes for hashtable hash and cmp functions 1c649aa qc_mysqlembedded: Include skygw_...h without path. d276160 Add missing RPM scripts e70e644 Fix HTTPAuth installation 1b2b389 Combine utils into the server directory 3ff9913 Add missing utils headers to devel package 407efb2 Fix minor packaging problems 99aa6ad Split MaxScale into core, experimental and devel packages 1290386 Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop e59f148 Make scripts POSIX sh compatible 7319266 Fixed SHOW SLAVE STATUS in bonlog router f8d760a Update Binlogrouter.md 0a904ed Update Replication-Proxy-Binlog-Router-Tutorial.md 75d4202 Update Replication-Proxy-Binlog-Router-Tutorial.md b8651fc Add missing newline in listmanager.h c7ad047 Add note about user data caches to release notes 70ccc2b Merge branch 'release-2.0.0' into develop 575d1b6 Mistake - dummy session needs list markers set. 8364508 Merge branch 'develop' into binlog_server_semisync 868b902 Update MaxScale limitations 2c8b327 Store listener caches in separate directories 6e183ec Create unique user data caches for each listeners f643685 Don't free orphaned tee filter sessions 4179afa Allow binlogrouter to be used without a listener 7ad79af Add function for freeing a listener 677a0a2 Move authentication data from services to listeners 4f12af7 Merge remote-tracking branch 'origin/MXS-677' into develop 1419b81 Semi-Sync support to binlog server: code review updtate 0ea0f01 Semi-Sync support to binlog server: added missing routine 4aad909 Semi-Sync support to binlog server b824e1e Add authenticator support to httpd.c 705a688 Change tabs to spaces d0c419e Change method of adding list fields to e.g. DCB 25504fc Document the changed routing priority of hints 41666d1 Remove use_ssl_if_enabled global option a3584e9 Make routing hints have highest priority 34a1d24 Updated document with new binlog router option 01eedc5 Updated documentation with SSL usage 8a4c0f6 Update Replication-Proxy-Binlog-Router-Tutorial.md 4e374aa Update Replication-Proxy-Binlog-Router-Tutorial.md f3f3c57 Update Replication-Proxy-Binlog-Router-Tutorial.md 617b79f Binlog Server: error messages typo fix fa8dfae Binlog Server: error messages review 1b8819c Fix freeing of schemarouter session memory 07f49e1 MXS-788: new code review fix 1fd3b09 MXS-788: show services now displays SSL info 6ca2584 MXS-788 code review fix ae6a7d0 MXS-788 code review 43d3474 Master server SSL connection 90b2377 Use correct variable in listmanager pre-allocation 9a5b238 Fix listmanager pre-allocation 9c78625 Fix a memory leak when backend authentication fails e59a966 Fix hang in list_find_free ff30223 Fix freeing of shared data in schemarouter fc8f9d3 Add missing include in luafilter ecf7f53 Add missing NULL value to filter parameter array 636d849 Update memory allocation approach f0d1d38 Add new allocation functions 97d00a0 Fix writing of uninitialized data to logs e72c9b2 Merge branch 'release-2.0.0' into develop cf2b712 Merge branch 'release-2.0.0' into develop 8917c5c Change the logic behind valid list entry checks c10deff Improve documentation about version_string f59f1f7 Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop c88edb3 Backend authentication failure improvement abd5bee Revert "Backend authentication failure improvement" 5bb3107 Backend authentication failure improvement b7f434a Add new allocation functions 3f022fa Fix stupid mistake 99c4317 Merge remote-tracking branch 'origin/MXS-677' into develop 3c1ded6 Added connection/authentication failure error reporting in SHOW SLAVE STATUS 0a60f7b Tidy up and deal with review points. ba103ff blr_slave.c: Update strncpy usage 467331e blr_master.c: Strncpy usage updates d2b7c0c Merge remote-tracking branch 'origin/develop-nullauth-merge' into develop 5a8c1d0 qc: Measure execution time at the right place. bccdb93 Merge branch 'NullAuthDeny' into develop 2e6511c Add 5.5.5 prefix to all version strings that lack it 314655a Improve DCB and session initialization and list handling e1c43f0 MXS-655: Make MaxScale logging logrotate(8) compatible ce36afd MXS-626: Don't log a header unless maxlog enabled dcd47a7 blr_file.c: Replace uses of strncpy 6b8f576 bls_slave.c: Replace strncpy with memcpy 68a0039 Add list preallocation, tidy up, simplify init. cb37d1b Fix copyright etc headers. 11a400d Tidy; comment; fix bad copies and mistakes. 7e36ec4 Add list manager files. c4794e3 Initial code for list manager. 1b42e25 Merge remote-tracking branch 'origin/MXS-765' into develop d50f617 Fix problems, extend tests, respond to review. dcb4a91 Filter test folder removed 0b60dbe Add a couple of comments. 83cdba0 Fix overwriting problem. ba5d353 Fix overwriting problem. 53671cb Small fixes in response to review. 173d049 blr.c: Review strncpy usage 4ff6ef2 binlog_common.c: Replace strncpy with memcpy f238e03 maxbinlogcheck.s: Replace strncpy 9807f8d harness: Replace unnecessary use of strncpy 8c7fe6a avro: Modify strncpy usage 9b8008e Small improvements. b7f784f Fix mistakes in testqueuemanager.c cc26962 Restore missing poll.c code; add testqueuemanager.c. 2e91806 Format the filter harness 22059e6 Initial implementation connection queueing. c604dc2 readwritesplit.c: Improve COM_INIT_DB handling 454d920 schemarouter.c: Replace strncpy with strcpy 8e85d66 sharding_common.c: Too long a database name handled explicitly 77f4446 Astyle schemarouter 491f7c2 maxinfo.c: Replace strncpy with memcpy 6b98105 maxinfo: Reformat with astyle c1dbf08 Handle oversize user and database names 5fa4a0f Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop 706963b BLR_DBUSERS_TAIL new var in blr.h d75b9af Tweak comments, remove trailing blanks. ab2400a Optimise statistics gathering by inline & simpler fns. fb59ddc Remove unnecessary strncpy/strncat usage in Binlog Server bdcd551 resultset.c: Change strncpy to memcpy c6b1c5e Reject rather than cut too long a path 6d8f112 Remove unnecessary strncpy/strncat usage 18bf5ed Remove unnecessary strncpy usage dc0e2db Make maxpasswd more userfriendly c9c8695 Fix calculation of padded_len in encryptPassword 2cfd2c6 dbusers.c: Check strncpy usage 7ab9342 Make more thorough checks in secrets_readKeys be7d593 Format cli.c debugcli.c testroute.c webserver.c 1ee5efb config.c: Check usage of strncpy 3043b12 gq_utils.c: Unnecessary use of strncpy removed 77874ac Add help to maxkeys 38392a3 Update secrets_writeKeys documentation 2d1325c Make SSL optional in MaxScale's own communication bda00da Fix avro build failures b2cb31a Add more OOM macros 41ccf17 Fix strdup usage a48f732 Fix realloc calls 20771f6 Add forgotten extern "C" block 8faf35a Add maxscale allocation functions bb47890 Add macros for OOM logging afea388 Fix silly mistakes. 6dafd22 Make deny default for null auth; move code from common to auth.
1911 lines
54 KiB
C
1911 lines
54 KiB
C
/*
|
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
|
*
|
|
* Change Date: 2019-07-01
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
|
|
/**
|
|
* @file debugcmd.c - The debug CLI command line interpreter
|
|
*
|
|
* The command interpreter for the dbug user interface. The command
|
|
* structure is such that there are a numerb of commands, notably
|
|
* show and a set of subcommands, the things to show in this case.
|
|
*
|
|
* Each subcommand has a handler function defined for it that is passeed
|
|
* the DCB to use to print the output of the commands and up to 3 arguments
|
|
* as numeric values.
|
|
*
|
|
* There are two "built in" commands, the help command and the quit
|
|
* command.
|
|
*
|
|
* @verbatim
|
|
* Revision History
|
|
*
|
|
* Date Who Description
|
|
* 20/06/13 Mark Riddoch Initial implementation
|
|
* 17/07/13 Mark Riddoch Additional commands
|
|
* 09/08/13 Massimiliano Pinto Added enable/disable commands (now only for log)
|
|
* 20/05/14 Mark Riddoch Added ability to give server and service names rather
|
|
* than simply addresses
|
|
* 23/05/14 Mark Riddoch Added support for developer and user modes
|
|
* 29/05/14 Mark Riddoch Add Filter support
|
|
* 16/10/14 Mark Riddoch Add show eventq
|
|
* 05/03/15 Massimiliano Pinto Added enable/disable feedback
|
|
* 27/05/15 Martin Brampton Add show persistent [server]
|
|
* 06/11/15 Martin Brampton Add show buffers (conditional compilation)
|
|
* 23/05/16 Massimiliano Pinto 'add user' and 'remove user'
|
|
* no longer accept password parameter
|
|
* 27/06/16 Martin Brampton Modify to work with list manager sessions
|
|
*
|
|
* @endverbatim
|
|
*/
|
|
#include <my_config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <service.h>
|
|
#include <session.h>
|
|
#include <router.h>
|
|
#include <filter.h>
|
|
#include <modules.h>
|
|
#include <atomic.h>
|
|
#include <server.h>
|
|
#include <spinlock.h>
|
|
#include <buffer.h>
|
|
#include <dcb.h>
|
|
#include <maxscale/poll.h>
|
|
#include <users.h>
|
|
#include <dbusers.h>
|
|
#include <maxconfig.h>
|
|
#include <telnetd.h>
|
|
#include <adminusers.h>
|
|
#include <monitor.h>
|
|
#include <debugcli.h>
|
|
#include <housekeeper.h>
|
|
#include <listmanager.h>
|
|
|
|
#include <skygw_utils.h>
|
|
#include <log_manager.h>
|
|
#include <sys/syslog.h>
|
|
|
|
#define MAXARGS 6
|
|
|
|
#define ARG_TYPE_ADDRESS 1
|
|
#define ARG_TYPE_STRING 2
|
|
#define ARG_TYPE_SERVICE 3
|
|
#define ARG_TYPE_SERVER 4
|
|
#define ARG_TYPE_DBUSERS 5
|
|
#define ARG_TYPE_SESSION 6
|
|
#define ARG_TYPE_DCB 7
|
|
#define ARG_TYPE_MONITOR 8
|
|
#define ARG_TYPE_FILTER 9
|
|
#define ARG_TYPE_NUMERIC 10
|
|
|
|
extern LIST_CONFIG SESSIONlist;
|
|
|
|
/**
|
|
* The subcommand structure
|
|
*
|
|
* These are the options that may be passed to a command
|
|
*/
|
|
struct subcommand {
|
|
char *arg1;
|
|
int n_args;
|
|
void (*fn)();
|
|
char *help;
|
|
char *devhelp;
|
|
int arg_types[3];
|
|
};
|
|
|
|
static void telnetdShowUsers(DCB *);
|
|
static void show_log_throttling(DCB *);
|
|
|
|
/**
|
|
* The subcommands of the show command
|
|
*/
|
|
struct subcommand showoptions[] = {
|
|
#if defined(BUFFER_TRACE)
|
|
{ "buffers", 0, dprintAllBuffers,
|
|
"Show all buffers with backtrace",
|
|
"Show all buffers with backtrace",
|
|
{0, 0, 0} },
|
|
#endif
|
|
{ "dcblist", 0, dprintDCBList,
|
|
"Show statistics for the list of all descriptor control blocks",
|
|
"Show statistics for the list of all descriptor control blocks",
|
|
{0, 0, 0} },
|
|
{ "dcbs", 0, dprintAllDCBs,
|
|
"Show all descriptor control blocks (network connections)",
|
|
"Show all descriptor control blocks (network connections)",
|
|
{0, 0, 0} },
|
|
{ "dcb", 1, dprintDCB,
|
|
"Show a single descriptor control block e.g. show dcb 0x493340",
|
|
"Show a single descriptor control block e.g. show dcb 0x493340",
|
|
{ARG_TYPE_DCB, 0, 0} },
|
|
{ "dbusers", 1, dcb_usersPrint,
|
|
"Show statistics and user names for a service's user table.\n"
|
|
"\t\tExample : show dbusers <service name>",
|
|
"Show statistics and user names for a service's user table.\n"
|
|
"\t\tExample : show dbusers <ptr of 'User's data' from services list>|<service name>",
|
|
{ARG_TYPE_DBUSERS, 0, 0} },
|
|
{ "epoll", 0, dprintPollStats,
|
|
"Show the poll statistics",
|
|
"Show the poll statistics",
|
|
{0, 0, 0} },
|
|
{ "eventq", 0, dShowEventQ,
|
|
"Show the queue of events waiting to be processed",
|
|
"Show the queue of events waiting to be processed",
|
|
{0, 0, 0} },
|
|
{ "eventstats", 0, dShowEventStats,
|
|
"Show the event statistics",
|
|
"Show the event statistics",
|
|
{0, 0, 0} },
|
|
{ "feedbackreport", 0, moduleShowFeedbackReport,
|
|
"Show the report of MaxScale loaded modules, suitable for Notification Service",
|
|
"Show the report of MaxScale loaded modules, suitable for Notification Service",
|
|
{0, 0, 0} },
|
|
{ "filter", 1, dprintFilter,
|
|
"Show details of a filter, called with a filter name",
|
|
"Show details of a filter, called with the address of a filter",
|
|
{ARG_TYPE_FILTER, 0, 0} },
|
|
{ "filters", 0, dprintAllFilters,
|
|
"Show all filters",
|
|
"Show all filters",
|
|
{0, 0, 0} },
|
|
{ "log_throttling", 0, show_log_throttling,
|
|
"Show the current log throttling setting (count, window (ms), suppression (ms))",
|
|
"Show the current log throttling setting (count, window (ms), suppression (ms))",
|
|
{0, 0, 0} },
|
|
{ "modules", 0, dprintAllModules,
|
|
"Show all currently loaded modules",
|
|
"Show all currently loaded modules",
|
|
{0, 0, 0} },
|
|
{ "monitor", 1, monitorShow,
|
|
"Show the monitor details",
|
|
"Show the monitor details",
|
|
{ARG_TYPE_MONITOR, 0, 0} },
|
|
{ "monitors", 0, monitorShowAll,
|
|
"Show the monitors that are configured",
|
|
"Show the monitors that are configured",
|
|
{0, 0, 0} },
|
|
{ "persistent", 1, dprintPersistentDCBs,
|
|
"Show persistent pool for a named server, e.g. show persistent dbnode1",
|
|
"Show persistent pool for a server, e.g. show persistent 0x485390. "
|
|
"The address may also be replaced with the server name from the configuration file",
|
|
{ARG_TYPE_SERVER, 0, 0} },
|
|
{ "server", 1, dprintServer,
|
|
"Show details for a named server, e.g. show server dbnode1",
|
|
"Show details for a server, e.g. show server 0x485390. The address may also be "
|
|
"repalced with the server name from the configuration file",
|
|
{ARG_TYPE_SERVER, 0, 0} },
|
|
{ "servers", 0, dprintAllServers,
|
|
"Show all configured servers",
|
|
"Show all configured servers",
|
|
{0, 0, 0} },
|
|
{ "serversjson", 0, dprintAllServersJson,
|
|
"Show all configured servers in JSON format",
|
|
"Show all configured servers in JSON format",
|
|
{0, 0, 0} },
|
|
{ "services", 0, dprintAllServices,
|
|
"Show all configured services in MaxScale",
|
|
"Show all configured services in MaxScale",
|
|
{0, 0, 0} },
|
|
{ "service", 1, dprintService,
|
|
"Show a single service in MaxScale, may be passed a service name",
|
|
"Show a single service in MaxScale, may be passed a service name or address of a service object",
|
|
{ARG_TYPE_SERVICE, 0, 0} },
|
|
{ "session", 1, dprintSession,
|
|
"Show a single session in MaxScale, e.g. show session 0x284830",
|
|
"Show a single session in MaxScale, e.g. show session 0x284830",
|
|
{ARG_TYPE_SESSION, 0, 0} },
|
|
{ "sessionlist", 0, dprintSessionList,
|
|
"Show statistics for the list of all sessions",
|
|
"Show statistics for the list of all sessions",
|
|
{0, 0, 0} },
|
|
{ "sessions", 0, dprintAllSessions,
|
|
"Show all active sessions in MaxScale",
|
|
"Show all active sessions in MaxScale",
|
|
{0, 0, 0} },
|
|
{ "tasks", 0, hkshow_tasks,
|
|
"Show all active housekeeper tasks in MaxScale",
|
|
"Show all active housekeeper tasks in MaxScale",
|
|
{0, 0, 0} },
|
|
{ "threads", 0, dShowThreads,
|
|
"Show the status of the polling threads in MaxScale",
|
|
"Show the status of the polling threads in MaxScale",
|
|
{0, 0, 0} },
|
|
{ "users", 0, telnetdShowUsers,
|
|
"Show statistics and user names for the debug interface",
|
|
"Show statistics and user names for the debug interface",
|
|
{0, 0, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
/**
|
|
* The subcommands of the list command
|
|
*/
|
|
struct subcommand listoptions[] = {
|
|
{ "clients", 0, dListClients,
|
|
"List all the client connections to MaxScale",
|
|
"List all the client connections to MaxScale",
|
|
{0, 0, 0} },
|
|
{ "dcbs", 0, dListDCBs,
|
|
"List all the DCBs active within MaxScale",
|
|
"List all the DCBs active within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "filters", 0, dListFilters,
|
|
"List all the filters defined within MaxScale",
|
|
"List all the filters defined within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "listeners", 0, dListListeners,
|
|
"List all the listeners defined within MaxScale",
|
|
"List all the listeners defined within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "modules", 0, dprintAllModules,
|
|
"List all currently loaded modules",
|
|
"List all currently loaded modules",
|
|
{0, 0, 0} },
|
|
{ "monitors", 0, monitorList,
|
|
"List all monitors",
|
|
"List all monitors",
|
|
{0, 0, 0} },
|
|
{ "services", 0, dListServices,
|
|
"List all the services defined within MaxScale",
|
|
"List all the services defined within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "servers", 0, dListServers,
|
|
"List all the servers defined within MaxScale",
|
|
"List all the servers defined within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "sessions", 0, dListSessions,
|
|
"List all the active sessions within MaxScale",
|
|
"List all the active sessions within MaxScale",
|
|
{0, 0, 0} },
|
|
{ "threads", 0, dShowThreads,
|
|
"List the status of the polling threads in MaxScale",
|
|
"List the status of the polling threads in MaxScale",
|
|
{0, 0, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
extern void shutdown_server();
|
|
static void shutdown_service(DCB *dcb, SERVICE *service);
|
|
static void shutdown_monitor(DCB *dcb, MONITOR *monitor);
|
|
|
|
/**
|
|
* The subcommands of the shutdown command
|
|
*/
|
|
struct subcommand shutdownoptions[] = {
|
|
{
|
|
"maxscale",
|
|
0,
|
|
shutdown_server,
|
|
"Shutdown MaxScale",
|
|
"Shutdown MaxScale",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
"monitor",
|
|
1,
|
|
shutdown_monitor,
|
|
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
|
|
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
|
|
{ARG_TYPE_MONITOR, 0, 0}
|
|
},
|
|
{
|
|
"service",
|
|
1,
|
|
shutdown_service,
|
|
"Shutdown a service, e.g. shutdown service \"Sales Database\"",
|
|
"Shutdown a service, e.g. shutdown service 0x4838320 or shutdown service \"Sales Database\"",
|
|
{ARG_TYPE_SERVICE, 0, 0}
|
|
},
|
|
{
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
{0, 0, 0}
|
|
}
|
|
};
|
|
|
|
static void sync_logs(DCB *dcb)
|
|
{
|
|
if (mxs_log_flush_sync() == 0)
|
|
{
|
|
dcb_printf(dcb, "Logs flushed to disk\n");
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Failed to flush logs to disk. Read the error log for "
|
|
"more details.\n");
|
|
}
|
|
}
|
|
|
|
struct subcommand syncoptions[] =
|
|
{
|
|
{
|
|
"logs",
|
|
0,
|
|
sync_logs,
|
|
"Flush log files to disk",
|
|
"Flush log files to disk",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
{0, 0, 0}
|
|
}
|
|
};
|
|
|
|
static void restart_service(DCB *dcb, SERVICE *service);
|
|
static void restart_monitor(DCB *dcb, MONITOR *monitor);
|
|
/**
|
|
* The subcommands of the restart command
|
|
*/
|
|
struct subcommand restartoptions[] = {
|
|
{ "monitor", 1, restart_monitor,
|
|
"Restart a monitor, e.g. restart monitor 0x48181e0",
|
|
"Restart a monitor, e.g. restart monitor 0x48181e0",
|
|
{ARG_TYPE_MONITOR, 0, 0} },
|
|
{ "service", 1, restart_service,
|
|
"Restart a service, e.g. restart service \"Test Service\"",
|
|
"Restart a service, e.g. restart service 0x4838320",
|
|
{ARG_TYPE_SERVICE, 0, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
static void set_server(DCB *dcb, SERVER *server, char *bit);
|
|
static void set_pollsleep(DCB *dcb, int);
|
|
static void set_nbpoll(DCB *dcb, int);
|
|
static void set_log_throttling(DCB *dcb, int count, int window_ms, int suppress_ms);
|
|
/**
|
|
* The subcommands of the set command
|
|
*/
|
|
struct subcommand setoptions[] = {
|
|
{ "server", 2, set_server,
|
|
"Set the status of a server. E.g. set server dbnode4 master",
|
|
"Set the status of a server. E.g. set server 0x4838320 master",
|
|
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
|
|
{ "pollsleep", 1, set_pollsleep,
|
|
"Set the maximum poll sleep period in milliseconds",
|
|
"Set the maximum poll sleep period in milliseconds",
|
|
{ARG_TYPE_NUMERIC, 0, 0} },
|
|
{ "nbpolls", 1, set_nbpoll,
|
|
"Set the number of non-blocking polls",
|
|
"Set the number of non-blocking polls",
|
|
{ARG_TYPE_NUMERIC, 0, 0} },
|
|
{ "log_throttling", 3, set_log_throttling,
|
|
"Set the log throttling configuration",
|
|
"Set the log throttling configuration",
|
|
{ARG_TYPE_NUMERIC, ARG_TYPE_NUMERIC, ARG_TYPE_NUMERIC} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
static void clear_server(DCB *dcb, SERVER *server, char *bit);
|
|
/**
|
|
* The subcommands of the clear command
|
|
*/
|
|
struct subcommand clearoptions[] = {
|
|
{ "server", 2, clear_server,
|
|
"Clear the status of a server. E.g. clear server dbnode2 master",
|
|
"Clear the status of a server. E.g. clear server 0x4838320 master",
|
|
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
static void reload_dbusers(DCB *dcb, SERVICE *service);
|
|
static void reload_config(DCB *dcb);
|
|
|
|
/**
|
|
* The subcommands of the reload command
|
|
*/
|
|
struct subcommand reloadoptions[] = {
|
|
{ "config", 0, reload_config,
|
|
"Reload the configuration data for MaxScale.",
|
|
"Reload the configuration data for MaxScale.",
|
|
{0, 0, 0} },
|
|
{ "dbusers", 1, reload_dbusers,
|
|
"Reload the dbuser data for a service. E.g. reload dbusers \"splitter service\"",
|
|
"Reload the dbuser data for a service. E.g. reload dbusers 0x849420",
|
|
{ARG_TYPE_SERVICE, 0, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
static void enable_log_action(DCB *, char *);
|
|
static void disable_log_action(DCB *, char *);
|
|
static void enable_log_priority(DCB *, char *);
|
|
static void disable_log_priority(DCB *, char *);
|
|
static void enable_sess_log_action(DCB *dcb, char *arg1, char *arg2);
|
|
static void disable_sess_log_action(DCB *dcb, char *arg1, char *arg2);
|
|
static void enable_sess_log_priority(DCB *dcb, char *arg1, char *arg2);
|
|
static void disable_sess_log_priority(DCB *dcb, char *arg1, char *arg2);
|
|
static void enable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor);
|
|
static void disable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor);
|
|
static void enable_service_root(DCB *dcb, SERVICE *service);
|
|
static void disable_service_root(DCB *dcb, SERVICE *service);
|
|
static void enable_feedback_action();
|
|
static void disable_feedback_action();
|
|
static void enable_syslog();
|
|
static void disable_syslog();
|
|
static void enable_maxlog();
|
|
static void disable_maxlog();
|
|
|
|
/**
|
|
* * The subcommands of the enable command
|
|
* */
|
|
struct subcommand enableoptions[] = {
|
|
{
|
|
"heartbeat",
|
|
1,
|
|
enable_monitor_replication_heartbeat,
|
|
"Enable the monitor replication heartbeat, pass a monitor name as argument",
|
|
"Enable the monitor replication heartbeat, pass a monitor name as argument",
|
|
{ARG_TYPE_MONITOR, 0, 0}
|
|
},
|
|
{
|
|
"log",
|
|
1,
|
|
enable_log_action,
|
|
"[deprecated] Enable Log options for MaxScale, options 'trace' | 'error' | 'message'."
|
|
"E.g. 'enable log message'.",
|
|
"[deprecated] Enable Log options for MaxScale, options 'trace' | 'error' | 'message'."
|
|
"E.g. 'enable log message'.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"log-priority",
|
|
1,
|
|
enable_log_priority,
|
|
"Enable a logging priority; options 'err' | 'warning' | 'notice' | 'info' | 'debug'. "
|
|
"E.g.: 'enable log-priority info'.",
|
|
"Enable a logging priority; options 'err' | 'warning' | 'notice' | 'info' | 'debug'. "
|
|
"E.g.: 'enable log-priority info'.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"sessionlog",
|
|
2,
|
|
enable_sess_log_action,
|
|
"[deprecated] Enable Log options for a single session. Usage: enable sessionlog [trace | error | "
|
|
"message | debug] <session id>\t E.g. enable sessionlog message 123.",
|
|
"[deprecated] Enable Log options for a single session. Usage: enable sessionlog [trace | error | "
|
|
"message | debug] <session id>\t E.g. enable sessionlog message 123.",
|
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
|
},
|
|
{
|
|
"sessionlog-priority",
|
|
2,
|
|
enable_sess_log_priority,
|
|
"Enable a logging priority for a particular session. "
|
|
"Usage: enable sessionlog-priority [err | warning | notice | info | debug] <session id>"
|
|
"message | debug] <session id>\t E.g. enable sessionlog-priority info 123.",
|
|
"Enable a logging priority for a particular session. "
|
|
"Usage: enable sessionlog-priority [err | warning | notice | info | debug] <session id>"
|
|
"message | debug] <session id>\t E.g. enable sessionlog-priority info 123.",
|
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
|
},
|
|
{
|
|
"root",
|
|
1,
|
|
enable_service_root,
|
|
"Enable root access to a service, pass a service name to enable root access",
|
|
"Enable root access to a service, pass a service name to enable root access",
|
|
{ARG_TYPE_SERVICE, 0, 0}
|
|
},
|
|
{
|
|
"feedback",
|
|
0,
|
|
enable_feedback_action,
|
|
"Enable MaxScale modules list sending via http to notification service",
|
|
"Enable MaxScale modules list sending via http to notification service",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
"syslog",
|
|
0,
|
|
enable_syslog,
|
|
"Enable syslog logging",
|
|
"Enable syslog logging",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
"maxlog",
|
|
0,
|
|
enable_maxlog,
|
|
"Enable maxlog logging",
|
|
"Enable maxlog logging",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
{0, 0, 0}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* * The subcommands of the disable command
|
|
* */
|
|
struct subcommand disableoptions[] = {
|
|
{
|
|
"heartbeat",
|
|
1,
|
|
disable_monitor_replication_heartbeat,
|
|
"Disable the monitor replication heartbeat",
|
|
"Disable the monitor replication heartbeat",
|
|
{ARG_TYPE_MONITOR, 0, 0}
|
|
},
|
|
{
|
|
"log",
|
|
1,
|
|
disable_log_action,
|
|
"[deprecated] Disable Log for MaxScale, Options: 'debug' | 'trace' | 'error' | 'message'."
|
|
"E.g. 'disable log debug'.",
|
|
"[deprecated] Disable Log for MaxScale, Options: 'debug' | 'trace' | 'error' | 'message'."
|
|
"E.g. 'disable log debug'.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"log-priority",
|
|
1,
|
|
disable_log_priority,
|
|
"Disable a logging priority; options 'err' | 'warning' | 'notice' | 'info' | 'debug'. "
|
|
"E.g.: 'disable log-priority info'.",
|
|
"Disable a logging priority; options 'err' | 'warning' | 'notice' | 'info' | 'debug'. "
|
|
"E.g.: 'disable log-priority info'.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"sessionlog",
|
|
2,
|
|
disable_sess_log_action,
|
|
"[deprecated] Disable Log options for a single session. Usage: disable sessionlog [trace | error | "
|
|
"message | debug] <session id>\t E.g. disable sessionlog message 123.",
|
|
"[deprecated] Disable Log options for a single session. Usage: disable sessionlog [trace | error | "
|
|
"message | debug] <session id>\t E.g. disable sessionlog message 123.",
|
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
|
},
|
|
{
|
|
"sessionlog-priority",
|
|
2,
|
|
disable_sess_log_priority,
|
|
"Disable a logging priority for a particular session. "
|
|
"Usage: disable sessionlog-priority [err | warning | notice | info | debug] <session id>"
|
|
"message | debug] <session id>\t E.g. enable sessionlog-priority info 123.",
|
|
"Enable a logging priority for a particular session. "
|
|
"Usage: disable sessionlog-priority [err | warning | notice | info | debug] <session id>"
|
|
"message | debug] <session id>\t E.g. enable sessionlog-priority info 123.",
|
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
|
},
|
|
{
|
|
"root",
|
|
1,
|
|
disable_service_root,
|
|
"Disable root access to a service",
|
|
"Disable root access to a service",
|
|
{ARG_TYPE_SERVICE, 0, 0}
|
|
},
|
|
{
|
|
"feedback",
|
|
0,
|
|
disable_feedback_action,
|
|
"Disable MaxScale modules list sending via http to notification service",
|
|
"Disable MaxScale modules list sending via http to notification service",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
"syslog",
|
|
0,
|
|
disable_syslog,
|
|
"Disable syslog logging",
|
|
"Disable syslog logging",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
"maxlog",
|
|
0,
|
|
disable_maxlog,
|
|
"Disable maxlog logging",
|
|
"Disable maxlog logging",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
{0, 0, 0}
|
|
}
|
|
};
|
|
|
|
#if defined(FAKE_CODE)
|
|
|
|
static void fail_backendfd(void);
|
|
static void fail_clientfd(void);
|
|
static void fail_accept(DCB* dcb, char* arg1, char* arg2);
|
|
/**
|
|
* * The subcommands of the fail command
|
|
* */
|
|
struct subcommand failoptions[] = {
|
|
{
|
|
"backendfd",
|
|
0,
|
|
fail_backendfd,
|
|
"Fail backend socket for next operation.",
|
|
"Fail backend socket for next operation.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"clientfd",
|
|
0,
|
|
fail_clientfd,
|
|
"Fail client socket for next operation.",
|
|
"Fail client socket for next operation.",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"accept",
|
|
2,
|
|
fail_accept,
|
|
"Fail to accept next client connection.",
|
|
"Fail to accept next client connection.",
|
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
|
},
|
|
{
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
{0, 0, 0}
|
|
}
|
|
};
|
|
#endif /* FAKE_CODE */
|
|
|
|
static void telnetdAddUser(DCB *, char *);
|
|
/**
|
|
* The subcommands of the add command
|
|
*/
|
|
struct subcommand addoptions[] = {
|
|
{ "user", 1, telnetdAddUser,
|
|
"Add a new user for the debug interface. E.g. add user john",
|
|
"Add a new user for the debug interface. E.g. add user john",
|
|
{ARG_TYPE_STRING, 0, 0} },
|
|
{ NULL, 0, NULL, NULL, NULL,
|
|
{0, 0, 0} }
|
|
};
|
|
|
|
|
|
static void telnetdRemoveUser(DCB *, char *);
|
|
/**
|
|
* The subcommands of the remove command
|
|
*/
|
|
struct subcommand removeoptions[] = {
|
|
{
|
|
"user",
|
|
1,
|
|
telnetdRemoveUser,
|
|
"Remove existing maxscale user. Example : remove user john",
|
|
"Remove existing maxscale user. Example : remove user john",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
NULL, 0, NULL, NULL, NULL, {0, 0, 0}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* User command to flush a single logfile
|
|
*
|
|
* @param pdcb The stream to write output to
|
|
* @param logname The name of the log
|
|
*/
|
|
static void
|
|
flushlog(DCB *pdcb, char *logname)
|
|
{
|
|
bool unrecognized = false;
|
|
bool deprecated = false;
|
|
|
|
if (!strcasecmp(logname, "error"))
|
|
{
|
|
deprecated = true;
|
|
}
|
|
else if (!strcasecmp(logname, "message"))
|
|
{
|
|
deprecated = true;
|
|
}
|
|
else if (!strcasecmp(logname, "trace"))
|
|
{
|
|
deprecated = true;
|
|
}
|
|
else if (!strcasecmp(logname, "debug"))
|
|
{
|
|
deprecated = true;
|
|
}
|
|
else if (!strcasecmp(logname, "maxscale"))
|
|
{
|
|
; // nop
|
|
}
|
|
else
|
|
{
|
|
unrecognized = true;
|
|
}
|
|
|
|
if (unrecognized)
|
|
{
|
|
dcb_printf(pdcb, "Unexpected logfile name '%s', expected: 'maxscale'.\n", logname);
|
|
}
|
|
else
|
|
{
|
|
mxs_log_rotate();
|
|
|
|
if (deprecated)
|
|
{
|
|
dcb_printf(pdcb,
|
|
"'%s' is deprecated, currently there is only one log 'maxscale', "
|
|
"which was rotated.\n", logname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User command to flush all logfiles
|
|
*
|
|
* @param pdcb The stream to write output to
|
|
*/
|
|
static void
|
|
flushlogs(DCB *pdcb)
|
|
{
|
|
mxs_log_rotate();
|
|
}
|
|
|
|
|
|
/**
|
|
* The subcommands of the flush command
|
|
*/
|
|
struct subcommand flushoptions[] = {
|
|
{
|
|
"log",
|
|
1,
|
|
flushlog,
|
|
"Flush the content of a log file, close that log, rename it and open a new log file",
|
|
"Flush the content of a log file, close that log, rename it and open a new log file",
|
|
{ARG_TYPE_STRING, 0, 0}
|
|
},
|
|
{
|
|
"logs",
|
|
0,
|
|
flushlogs,
|
|
"Flush the content of all log files, close those logs, rename them and open a new log files",
|
|
"Flush the content of all log files, close those logs, rename them and open a new log files",
|
|
{0, 0, 0}
|
|
},
|
|
{
|
|
NULL, 0, NULL, NULL, NULL, {0, 0, 0}
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* The debug command table
|
|
*/
|
|
static struct {
|
|
char *cmd;
|
|
struct subcommand *options;
|
|
} cmds[] = {
|
|
{ "add", addoptions },
|
|
{ "clear", clearoptions },
|
|
{ "disable", disableoptions },
|
|
{ "enable", enableoptions },
|
|
#if defined(FAKE_CODE)
|
|
{ "fail", failoptions },
|
|
#endif /* FAKE_CODE */
|
|
{ "flush", flushoptions },
|
|
{ "list", listoptions },
|
|
{ "reload", reloadoptions },
|
|
{ "remove", removeoptions },
|
|
{ "restart", restartoptions },
|
|
{ "set", setoptions },
|
|
{ "show", showoptions },
|
|
{ "shutdown", shutdownoptions },
|
|
{ "sync", syncoptions },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
/**
|
|
* Convert a string argument to a numeric, observing prefixes
|
|
* for number bases, e.g. 0x for hex, 0 for octal
|
|
*
|
|
* @param mode The CLI mode
|
|
* @param arg The string representation of the argument
|
|
* @param arg_type The target type for the argument
|
|
* @return The argument as a long integer
|
|
*/
|
|
static unsigned long
|
|
convert_arg(int mode, char *arg, int arg_type)
|
|
{
|
|
unsigned long rval;
|
|
SERVICE *service;
|
|
|
|
switch (arg_type)
|
|
{
|
|
case ARG_TYPE_ADDRESS:
|
|
return (unsigned long)strtol(arg, NULL, 0);
|
|
case ARG_TYPE_STRING:
|
|
return (unsigned long)arg;
|
|
case ARG_TYPE_SERVICE:
|
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
|
{
|
|
rval = (unsigned long)service_find(arg);
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_SERVER:
|
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
|
{
|
|
rval = (unsigned long)server_find_by_unique_name(arg);
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_DBUSERS:
|
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
|
{
|
|
service = service_find(arg);
|
|
if (service)
|
|
{
|
|
return (unsigned long)(service->ports->users);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_DCB:
|
|
rval = (unsigned long)strtol(arg, NULL, 0);
|
|
if (mode == CLIM_USER && dcb_isvalid((DCB *)rval) == 0)
|
|
{
|
|
rval = 0;
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_SESSION:
|
|
rval = (unsigned long)strtol(arg, NULL, 0);
|
|
if (mode == CLIM_USER && session_isvalid((SESSION *)rval) == 0)
|
|
{
|
|
rval = 0;
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_MONITOR:
|
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
|
{
|
|
rval = (unsigned long)monitor_find(arg);
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_FILTER:
|
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
|
{
|
|
rval = (unsigned long)filter_find(arg);
|
|
}
|
|
return rval;
|
|
case ARG_TYPE_NUMERIC:
|
|
{
|
|
int i;
|
|
for (i = 0; arg[i]; i++)
|
|
{
|
|
if (arg[i] < '0' || arg[i] > '9')
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return atoi(arg);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* We have a complete line from the user, lookup the commands and execute them
|
|
*
|
|
* Commands are tokenised based on white space and then the first
|
|
* word is checked againts the cmds table. If a match is found the
|
|
* second word is compared to the different options for that command.
|
|
*
|
|
* Commands may also take up to 3 additional arguments, these are all
|
|
* assumed to the numeric values and will be converted before being passed
|
|
* to the handler function for the command.
|
|
*
|
|
* @param cli The CLI_SESSION
|
|
* @return Returns 0 if the interpreter should exit
|
|
*/
|
|
int
|
|
execute_cmd(CLI_SESSION *cli)
|
|
{
|
|
DCB *dcb = cli->session->client_dcb;
|
|
int argc, i, j, found = 0;
|
|
char *args[MAXARGS + 1];
|
|
unsigned long arg1, arg2, arg3;
|
|
int in_quotes = 0, escape_next = 0;
|
|
char *ptr, *lptr;
|
|
bool in_space = false;
|
|
int nskip = 0;
|
|
|
|
args[0] = cli->cmdbuf;
|
|
ptr = args[0];
|
|
lptr = ptr;
|
|
i = 0;
|
|
/*
|
|
* Break the command line into a number of words. Whitespace is used
|
|
* to delimit words and may be escaped by use of the \ character or
|
|
* the use of double quotes.
|
|
* The array args contains the broken down words, one per index.
|
|
*/
|
|
|
|
while (*ptr)
|
|
{
|
|
if (escape_next)
|
|
{
|
|
*lptr++ = *ptr++;
|
|
escape_next = 0;
|
|
}
|
|
else if (*ptr == '\\')
|
|
{
|
|
escape_next = 1;
|
|
ptr++;
|
|
}
|
|
else if (in_quotes == 0 && ((in_space = *ptr == ' ') || *ptr == '\t' || *ptr == '\r' || *ptr == '\n'))
|
|
{
|
|
|
|
*lptr = 0;
|
|
lptr += nskip;
|
|
nskip = 0;
|
|
|
|
if (!in_space)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (args[i] == ptr)
|
|
{
|
|
args[i] = ptr + 1;
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
if (i >= MAXARGS - 1)
|
|
{
|
|
break;
|
|
}
|
|
args[i] = ptr + 1;
|
|
}
|
|
ptr++;
|
|
lptr++;
|
|
}
|
|
else if (*ptr == '\"' && in_quotes == 0)
|
|
{
|
|
in_quotes = 1;
|
|
ptr++;
|
|
nskip++;
|
|
}
|
|
else if (*ptr == '\"' && in_quotes == 1)
|
|
{
|
|
in_quotes = 0;
|
|
ptr++;
|
|
nskip++;
|
|
}
|
|
else
|
|
{
|
|
*lptr++ = *ptr++;
|
|
}
|
|
}
|
|
*lptr = 0;
|
|
args[MIN(MAXARGS - 1, i + 1)] = NULL;
|
|
|
|
if (args[0] == NULL || *args[0] == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
for (i = 0; args[i] && *args[i]; i++)
|
|
;
|
|
argc = i - 2; /* The number of extra arguments to commands */
|
|
|
|
if (!strcasecmp(args[0], "help"))
|
|
{
|
|
if (args[1] == NULL || *args[1] == 0)
|
|
{
|
|
found = 1;
|
|
dcb_printf(dcb, "Available commands:\n");
|
|
for (i = 0; cmds[i].cmd; i++)
|
|
{
|
|
if (cmds[i].options[1].arg1 == NULL)
|
|
{
|
|
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[0].arg1);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, " %s [", cmds[i].cmd);
|
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
|
{
|
|
dcb_printf(dcb, "%s%s", cmds[i].options[j].arg1,
|
|
cmds[i].options[j + 1].arg1 ? "|" : "");
|
|
}
|
|
dcb_printf(dcb, "]\n");
|
|
}
|
|
}
|
|
dcb_printf(dcb, "\nType help command to see details of each command.\n");
|
|
dcb_printf(dcb, "Where commands require names as arguments and these names contain\n");
|
|
dcb_printf(dcb, "whitespace either the \\ character may be used to escape the whitespace\n");
|
|
dcb_printf(dcb, "or the name may be enclosed in double quotes \".\n\n");
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; cmds[i].cmd; i++)
|
|
{
|
|
if (!strcasecmp(args[1], cmds[i].cmd))
|
|
{
|
|
found = 1;
|
|
dcb_printf(dcb, "Available options to the %s command:\n", args[1]);
|
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
|
{
|
|
dcb_printf(dcb, " %-12s %s\n", cmds[i].options[j].arg1,
|
|
cmds[i].options[j].help);
|
|
}
|
|
}
|
|
}
|
|
if (found == 0)
|
|
{
|
|
dcb_printf(dcb, "No command %s to offer help with\n", args[1]);
|
|
}
|
|
}
|
|
found = 1;
|
|
}
|
|
else if (!strcasecmp(args[0], "quit"))
|
|
{
|
|
return 0;
|
|
}
|
|
else if (argc >= 0)
|
|
{
|
|
for (i = 0; cmds[i].cmd; i++)
|
|
{
|
|
if (strcasecmp(args[0], cmds[i].cmd) == 0)
|
|
{
|
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
|
{
|
|
if (strcasecmp(args[1], cmds[i].options[j].arg1) == 0)
|
|
{
|
|
found = 1; /**< command and sub-command match */
|
|
if (argc != cmds[i].options[j].n_args)
|
|
{
|
|
dcb_printf(dcb, "Incorrect number of arguments: %s %s expects %d arguments\n",
|
|
cmds[i].cmd, cmds[i].options[j].arg1,
|
|
cmds[i].options[j].n_args);
|
|
}
|
|
else
|
|
{
|
|
switch (cmds[i].options[j].n_args)
|
|
{
|
|
case 0:
|
|
cmds[i].options[j].fn(dcb);
|
|
break;
|
|
case 1:
|
|
arg1 = convert_arg(cli->mode, args[2], cmds[i].options[j].arg_types[0]);
|
|
|
|
if (arg1)
|
|
{
|
|
cmds[i].options[j].fn(dcb, arg1);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[2]);
|
|
}
|
|
break;
|
|
case 2:
|
|
arg1 = convert_arg(cli->mode, args[2], cmds[i].options[j].arg_types[0]);
|
|
arg2 = convert_arg(cli->mode, args[3], cmds[i].options[j].arg_types[1]);
|
|
if (arg1 && arg2)
|
|
{
|
|
cmds[i].options[j].fn(dcb, arg1, arg2);
|
|
}
|
|
else if (arg1 == 0)
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[2]);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[3]);
|
|
}
|
|
break;
|
|
case 3:
|
|
arg1 = convert_arg(cli->mode, args[2], cmds[i].options[j].arg_types[0]);
|
|
arg2 = convert_arg(cli->mode, args[3], cmds[i].options[j].arg_types[1]);
|
|
arg3 = convert_arg(cli->mode, args[4], cmds[i].options[j].arg_types[2]);
|
|
if (arg1 && arg2 && arg3)
|
|
{
|
|
cmds[i].options[j].fn(dcb, arg1, arg2, arg3);
|
|
}
|
|
else if (arg1 == 0)
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[2]);
|
|
}
|
|
else if (arg2 == 0)
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[3]);
|
|
}
|
|
else if (arg3 == 0)
|
|
{
|
|
dcb_printf(dcb, "Invalid argument: %s\n",
|
|
args[4]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
dcb_printf(dcb,
|
|
"Unknown or missing option for the %s command. Valid sub-commands are:\n",
|
|
cmds[i].cmd);
|
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
|
{
|
|
dcb_printf(dcb, " %-10s %s\n", cmds[i].options[j].arg1,
|
|
cmds[i].options[j].help);
|
|
}
|
|
found = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (argc == -1)
|
|
{
|
|
dcb_printf(dcb,
|
|
"Commands must consist of at least two words. Type help for a list of commands\n");
|
|
found = 1;
|
|
}
|
|
if (!found)
|
|
{
|
|
dcb_printf(dcb,
|
|
"Command '%s' not known, type help for a list of available commands\n", args[0]);
|
|
}
|
|
|
|
memset(cli->cmdbuf, 0, CMDBUFLEN);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Debug command to stop a service
|
|
*
|
|
* @param dcb The DCB to print any output to
|
|
* @param service The service to shutdown
|
|
*/
|
|
static void
|
|
shutdown_service(DCB *dcb, SERVICE *service)
|
|
{
|
|
serviceStop(service);
|
|
}
|
|
|
|
/**
|
|
* Debug command to restart a stopped service
|
|
*
|
|
* @param dcb The DCB to print any output to
|
|
* @param service The service to restart
|
|
*/
|
|
static void
|
|
restart_service(DCB *dcb, SERVICE *service)
|
|
{
|
|
serviceRestart(service);
|
|
}
|
|
|
|
/**
|
|
* Set the status bit of a server
|
|
*
|
|
* @param dcb DCB to send output to
|
|
* @param server The server to set the status of
|
|
* @param bit String representation of the status bit
|
|
*/
|
|
static void
|
|
set_server(DCB *dcb, SERVER *server, char *bit)
|
|
{
|
|
unsigned int bitvalue;
|
|
|
|
if ((bitvalue = server_map_status(bit)) != 0)
|
|
{
|
|
server_set_status(server, bitvalue);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Unknown status bit %s\n", bit);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Clear the status bit of a server
|
|
*
|
|
* @param dcb DCB to send output to
|
|
* @param server The server to set the status of
|
|
* @param bit String representation of the status bit
|
|
*/
|
|
static void
|
|
clear_server(DCB *dcb, SERVER *server, char *bit)
|
|
{
|
|
unsigned int bitvalue;
|
|
|
|
if ((bitvalue = server_map_status(bit)) != 0)
|
|
{
|
|
server_clear_status(server, bitvalue);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Unknown status bit %s\n", bit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reload the authenticaton data from the backend database of a service.
|
|
*
|
|
* @param dcb DCB to send output
|
|
* @param service The service to update
|
|
*/
|
|
static void
|
|
reload_dbusers(DCB *dcb, SERVICE *service)
|
|
{
|
|
dcb_printf(dcb, "Loaded %d database users for service %s.\n",
|
|
reload_mysql_users(service->ports), service->name);
|
|
}
|
|
|
|
/**
|
|
* Relaod the configuration data from the config file
|
|
*
|
|
* @param dcb DCB to use to send output
|
|
*/
|
|
static void
|
|
reload_config(DCB *dcb)
|
|
{
|
|
dcb_printf(dcb, "Reloading configuration from file.\n");
|
|
config_reload();
|
|
}
|
|
|
|
/**
|
|
* Add a new maxscale admin user
|
|
*
|
|
* @param dcb The DCB for messages
|
|
* @param user The user name
|
|
*/
|
|
static void
|
|
telnetdAddUser(DCB *dcb, char *user)
|
|
{
|
|
char *err;
|
|
|
|
if (admin_search_user(user))
|
|
{
|
|
dcb_printf(dcb, "User %s already exists.\n", user);
|
|
return;
|
|
}
|
|
|
|
if ((err = admin_add_user(user)) == NULL)
|
|
{
|
|
dcb_printf(dcb, "User %s has been successfully added.\n", user);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Failed to add new user. %s\n", err);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove a maxscale admin user
|
|
*
|
|
* @param dcb The DCB for messages
|
|
* @param user The user name
|
|
*/
|
|
static void telnetdRemoveUser(
|
|
DCB* dcb,
|
|
char* user)
|
|
{
|
|
char* err;
|
|
|
|
if (!admin_search_user(user))
|
|
{
|
|
dcb_printf(dcb, "User %s doesn't exist.\n", user);
|
|
return;
|
|
}
|
|
|
|
if ((err = admin_remove_user(user)) == NULL)
|
|
{
|
|
dcb_printf(dcb, "User %s has been successfully removed.\n", user);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "Failed to remove user %s. %s\n", user, err);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Print the adminsitration users
|
|
*
|
|
* @param dcb The DCB to print the user data to
|
|
*/
|
|
static void
|
|
telnetdShowUsers(DCB *dcb)
|
|
{
|
|
dcb_printf(dcb, "Administration interface users:\n");
|
|
dcb_PrintAdminUsers(dcb);
|
|
}
|
|
|
|
/**
|
|
* Print the log throttling state
|
|
*
|
|
* @param dcb The DCB to print the state to.
|
|
*/
|
|
static void
|
|
show_log_throttling(DCB *dcb)
|
|
{
|
|
MXS_LOG_THROTTLING t;
|
|
mxs_log_get_throttling(&t);
|
|
|
|
dcb_printf(dcb, "%lu %lu %lu\n", t.count, t.window_ms, t.suppress_ms);
|
|
}
|
|
|
|
/**
|
|
* Command to shutdown a running monitor
|
|
*
|
|
* @param dcb The DCB to use to print messages
|
|
* @param monitor The monitor to shutdown
|
|
*/
|
|
static void
|
|
shutdown_monitor(DCB *dcb, MONITOR *monitor)
|
|
{
|
|
monitorStop(monitor);
|
|
}
|
|
|
|
/**
|
|
* Command to restart a stopped monitor
|
|
*
|
|
* @param dcb The DCB to use to print messages
|
|
* @param monitor The monitor to restart
|
|
*/
|
|
static void
|
|
restart_monitor(DCB *dcb, MONITOR *monitor)
|
|
{
|
|
monitorStart(monitor, NULL);
|
|
}
|
|
|
|
/**
|
|
* Enable replication heartbeat for a monitor
|
|
*
|
|
* @param dcb Connection to user interface
|
|
* @param monitor The monitor
|
|
*/
|
|
static void
|
|
enable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor)
|
|
{
|
|
CONFIG_PARAMETER param;
|
|
const char* name = "detect_replication_lag";
|
|
const char* value = "1";
|
|
param.name = (char*)name;
|
|
param.value = (char*)value;
|
|
param.next = NULL;
|
|
monitorStop(monitor);
|
|
monitorStart(monitor, ¶m);
|
|
}
|
|
|
|
/**
|
|
* Disable replication heartbeat for a monitor
|
|
*
|
|
* @param dcb Connection to user interface
|
|
* @param monitor The monitor
|
|
*/
|
|
static void
|
|
disable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor)
|
|
{
|
|
CONFIG_PARAMETER param;
|
|
const char* name = "detect_replication_lag";
|
|
const char* value = "0";
|
|
param.name = (char*)name;
|
|
param.value = (char*)value;
|
|
param.next = NULL;
|
|
monitorStop(monitor);
|
|
monitorStart(monitor, ¶m);
|
|
}
|
|
|
|
/**
|
|
* Enable root access to a service
|
|
*
|
|
* @param dcb Connection to user interface
|
|
* @param service The service
|
|
*/
|
|
static void
|
|
enable_service_root(DCB *dcb, SERVICE *service)
|
|
{
|
|
serviceEnableRootUser(service, 1);
|
|
}
|
|
|
|
/**
|
|
* Disable root access to a service
|
|
*
|
|
* @param dcb Connection to user interface
|
|
* @param service The service
|
|
*/
|
|
static void
|
|
disable_service_root(DCB *dcb, SERVICE *service)
|
|
{
|
|
serviceEnableRootUser(service, 0);
|
|
}
|
|
|
|
struct log_action_entry
|
|
{
|
|
const char* name;
|
|
int priority;
|
|
const char* replacement;
|
|
};
|
|
|
|
static bool get_log_action(const char* name, struct log_action_entry* entryp)
|
|
{
|
|
static const struct log_action_entry entries[] =
|
|
{
|
|
{ "debug", LOG_DEBUG, "debug" },
|
|
{ "trace", LOG_INFO, "info" },
|
|
{ "message", LOG_NOTICE, "notice" },
|
|
};
|
|
const int n_entries = sizeof(entries) / sizeof(entries[0]);
|
|
|
|
bool found = false;
|
|
int i = 0;
|
|
|
|
while (!found && (i < n_entries))
|
|
{
|
|
if (strcmp(name, entries[i].name) == 0)
|
|
{
|
|
*entryp = entries[i];
|
|
found = true;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
/**
|
|
* Enables a log for a single session
|
|
* @param session The session in question
|
|
* @param dcb Client DCB
|
|
* @param type Which log to enable
|
|
*/
|
|
static void enable_sess_log_action(DCB *dcb, char *arg1, char *arg2)
|
|
{
|
|
struct log_action_entry entry;
|
|
|
|
if (get_log_action(arg1, &entry))
|
|
{
|
|
size_t id = (size_t) strtol(arg2, 0, 0);
|
|
list_entry_t *current = list_start_iteration(&SESSIONlist);
|
|
while (current)
|
|
{
|
|
SESSION *session = (SESSION *)current;
|
|
if (session->ses_id == id)
|
|
{
|
|
session_enable_log_priority(session, entry.priority);
|
|
list_terminate_iteration_early(&SESSIONlist, current);
|
|
break;
|
|
}
|
|
current = list_iterate(&SESSIONlist, current);
|
|
}
|
|
|
|
if (!current)
|
|
{
|
|
dcb_printf(dcb, "Session not found: %s.\n", arg2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "%s is not supported for enable log.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disables a log for a single session
|
|
* @param session The session in question
|
|
* @param dcb Client DCB
|
|
* @param type Which log to disable
|
|
*/
|
|
static void disable_sess_log_action(DCB *dcb, char *arg1, char *arg2)
|
|
{
|
|
struct log_action_entry entry;
|
|
|
|
if (get_log_action(arg1, &entry))
|
|
{
|
|
size_t id = (size_t) strtol(arg2, 0, 0);
|
|
list_entry_t *current = list_start_iteration(&SESSIONlist);
|
|
while (current)
|
|
{
|
|
SESSION *session = (SESSION *)current;
|
|
if (session->ses_id == id)
|
|
{
|
|
session_disable_log_priority(session, entry.priority);
|
|
list_terminate_iteration_early(&SESSIONlist, current);
|
|
break;
|
|
}
|
|
current = list_iterate(&SESSIONlist, current);
|
|
}
|
|
|
|
if (!current)
|
|
{
|
|
dcb_printf(dcb, "Session not found: %s.\n", arg2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "%s is not supported for disable log.\n", arg1);
|
|
}
|
|
}
|
|
|
|
struct log_priority_entry
|
|
{
|
|
const char* name;
|
|
int priority;
|
|
};
|
|
|
|
static int compare_log_priority_entries(const void* l, const void* r)
|
|
{
|
|
const struct log_priority_entry* l_entry = (const struct log_priority_entry*) l;
|
|
const struct log_priority_entry* r_entry = (const struct log_priority_entry*) r;
|
|
|
|
return strcmp(l_entry->name, r_entry->name);
|
|
}
|
|
|
|
static int string_to_priority(const char* name)
|
|
{
|
|
static const struct log_priority_entry LOG_PRIORITY_ENTRIES[] =
|
|
{
|
|
// NOTE: If you make changes to this array, ensure that it remains alphabetically ordered.
|
|
{ "debug", LOG_DEBUG },
|
|
{ "info", LOG_INFO },
|
|
{ "notice", LOG_NOTICE },
|
|
{ "warning", LOG_WARNING },
|
|
};
|
|
|
|
const size_t N_LOG_PRIORITY_ENTRIES = sizeof(LOG_PRIORITY_ENTRIES) / sizeof(LOG_PRIORITY_ENTRIES[0]);
|
|
|
|
struct log_priority_entry key = { name, -1 };
|
|
struct log_priority_entry* result = bsearch(&key,
|
|
LOG_PRIORITY_ENTRIES,
|
|
N_LOG_PRIORITY_ENTRIES,
|
|
sizeof(struct log_priority_entry),
|
|
compare_log_priority_entries);
|
|
|
|
return result ? result->priority : -1;
|
|
}
|
|
|
|
/**
|
|
* Enables a log priority for a single session
|
|
* @param session The session in question
|
|
* @param dcb Client DCB
|
|
* @param type Which log to enable
|
|
*/
|
|
static void enable_sess_log_priority(DCB *dcb, char *arg1, char *arg2)
|
|
{
|
|
int priority = string_to_priority(arg1);
|
|
|
|
if (priority != -1)
|
|
{
|
|
size_t id = (size_t) strtol(arg2, 0, 0);
|
|
list_entry_t *current = list_start_iteration(&SESSIONlist);
|
|
while (current)
|
|
{
|
|
SESSION *session = (SESSION *)current;
|
|
if (session->ses_id == id)
|
|
{
|
|
session_enable_log_priority(session, priority);
|
|
list_terminate_iteration_early(&SESSIONlist, current);
|
|
break;
|
|
}
|
|
current = list_iterate(&SESSIONlist, current);
|
|
}
|
|
|
|
if (!current)
|
|
{
|
|
dcb_printf(dcb, "Session not found: %s.\n", arg2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not a supported log priority.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disable a log priority for a single session
|
|
* @param session The session in question
|
|
* @param dcb Client DCB
|
|
* @param type Which log to enable
|
|
*/
|
|
static void disable_sess_log_priority(DCB *dcb, char *arg1, char *arg2)
|
|
{
|
|
int priority = string_to_priority(arg1);
|
|
|
|
if (priority != -1)
|
|
{
|
|
size_t id = (size_t) strtol(arg2, 0, 0);
|
|
list_entry_t *current = list_start_iteration(&SESSIONlist);
|
|
while (current)
|
|
{
|
|
SESSION *session = (SESSION *)current;
|
|
if (session->ses_id == id)
|
|
{
|
|
session_disable_log_priority(session, priority);
|
|
list_terminate_iteration_early(&SESSIONlist, current);
|
|
break;
|
|
}
|
|
current = list_iterate(&SESSIONlist, current);
|
|
}
|
|
|
|
if (!current)
|
|
{
|
|
dcb_printf(dcb, "Session not found: %s.\n", arg2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not a supported log priority.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The log enable action
|
|
*/
|
|
static void enable_log_action(DCB *dcb, char *arg1)
|
|
{
|
|
struct log_action_entry entry;
|
|
|
|
if (get_log_action(arg1, &entry))
|
|
{
|
|
mxs_log_set_priority_enabled(entry.priority, true);
|
|
|
|
dcb_printf(dcb,
|
|
"'enable log %s' is accepted but deprecated, use 'enable log-priority %s' instead.\n",
|
|
arg1, entry.replacement);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not supported for enable log.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The log disable action
|
|
*/
|
|
static void disable_log_action(DCB *dcb, char *arg1)
|
|
{
|
|
struct log_action_entry entry;
|
|
|
|
if (get_log_action(arg1, &entry))
|
|
{
|
|
mxs_log_set_priority_enabled(entry.priority, false);
|
|
|
|
dcb_printf(dcb,
|
|
"'disable log %s' is accepted but deprecated, use 'enable log-priority %s' instead.\n",
|
|
arg1, entry.replacement);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not supported for 'disable log'.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The log-priority enable action
|
|
*/
|
|
|
|
static void enable_log_priority(DCB *dcb, char *arg1)
|
|
{
|
|
int priority = string_to_priority(arg1);
|
|
|
|
if (priority != -1)
|
|
{
|
|
mxs_log_set_priority_enabled(priority, true);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not a supported log priority.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The log-priority disable action
|
|
*/
|
|
|
|
static void disable_log_priority(DCB *dcb, char *arg1)
|
|
{
|
|
int priority = string_to_priority(arg1);
|
|
|
|
if (priority != -1)
|
|
{
|
|
mxs_log_set_priority_enabled(priority, false);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb, "'%s' is not a supported log priority.\n", arg1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the duration of the sleep passed to the poll wait
|
|
*
|
|
* @param dcb DCB for output
|
|
* @param sleeptime Sleep time in milliseconds
|
|
*/
|
|
static void
|
|
set_pollsleep(DCB *dcb, int sleeptime)
|
|
{
|
|
poll_set_maxwait(sleeptime);
|
|
}
|
|
|
|
/**
|
|
* Set the number of non-blockign spins to make
|
|
*
|
|
* @param dcb DCB for output
|
|
* @param nb Number of spins
|
|
*/
|
|
static void
|
|
set_nbpoll(DCB *dcb, int nb)
|
|
{
|
|
poll_set_nonblocking_polls(nb);
|
|
}
|
|
|
|
static void
|
|
set_log_throttling(DCB *dcb, int count, int window_ms, int suppress_ms)
|
|
{
|
|
if ((count >= 0) || (window_ms >= 0) || (suppress_ms >= 0))
|
|
{
|
|
MXS_LOG_THROTTLING t = { count, window_ms, suppress_ms };
|
|
|
|
mxs_log_set_throttling(&t);
|
|
}
|
|
else
|
|
{
|
|
dcb_printf(dcb,
|
|
"set log_throttling expect 3 integers X Y Z, equal to or larger than 0, "
|
|
"where the X denotes how many times particular message may be logged "
|
|
"during a period of Y milliseconds before it is suppressed for Z milliseconds.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-enable sendig MaxScale module list via http
|
|
* Proper [feedback] section in MaxSclale.cnf
|
|
* is required.
|
|
*/
|
|
static void
|
|
enable_feedback_action(void)
|
|
{
|
|
config_enable_feedback_task();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Disable sendig MaxScale module list via http
|
|
*/
|
|
|
|
static void
|
|
disable_feedback_action(void)
|
|
{
|
|
config_disable_feedback_task();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Enable syslog logging.
|
|
*/
|
|
static void
|
|
enable_syslog()
|
|
{
|
|
mxs_log_set_syslog_enabled(true);
|
|
}
|
|
|
|
/**
|
|
* Disable syslog logging.
|
|
*/
|
|
static void
|
|
disable_syslog()
|
|
{
|
|
mxs_log_set_syslog_enabled(false);
|
|
}
|
|
|
|
/**
|
|
* Enable maxlog logging.
|
|
*/
|
|
static void
|
|
enable_maxlog()
|
|
{
|
|
mxs_log_set_maxlog_enabled(true);
|
|
}
|
|
|
|
/**
|
|
* Disable maxlog logging.
|
|
*/
|
|
static void
|
|
disable_maxlog()
|
|
{
|
|
mxs_log_set_maxlog_enabled(false);
|
|
}
|
|
|
|
#if defined(FAKE_CODE)
|
|
static void fail_backendfd(void)
|
|
{
|
|
fail_next_backend_fd = true;
|
|
}
|
|
|
|
static void fail_clientfd(void)
|
|
{
|
|
fail_next_client_fd = true;
|
|
}
|
|
|
|
static void fail_accept(
|
|
DCB* dcb,
|
|
char* arg1,
|
|
char* arg2)
|
|
{
|
|
int failcount = MIN(atoi(arg2), 100);
|
|
fail_accept_errno = atoi(arg1);
|
|
char errbuf[STRERROR_BUFLEN];
|
|
|
|
switch(fail_accept_errno) {
|
|
case EAGAIN:
|
|
// case EWOULDBLOCK:
|
|
case EBADF:
|
|
case EINTR:
|
|
case EINVAL:
|
|
case EMFILE:
|
|
case ENFILE:
|
|
case ENOTSOCK:
|
|
case EOPNOTSUPP:
|
|
case ENOBUFS:
|
|
case ENOMEM:
|
|
case EPROTO:
|
|
fail_next_accept = failcount;
|
|
break;
|
|
|
|
default:
|
|
dcb_printf(dcb,
|
|
"[%d, %s] is not valid errno for accept.\n",
|
|
fail_accept_errno,
|
|
strerror_r(fail_accept_errno, errbuf, sizeof(errbuf)));
|
|
return ;
|
|
}
|
|
}
|
|
#endif /* FAKE_CODE */
|