1 /* Copyright (c) 2003-2007 MySQL AB
2    Use is subject to license terms
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include <ndb_global.h>
18 #include <my_sys.h>
19 #include <Vector.hpp>
20 #include <mgmapi.h>
21 #include <util/BaseString.hpp>
22 #include <ndbd_exit_codes.h>
23 
24 class MgmtSrvr;
25 
26 /**
27  *  @class CommandInterpreter
28  *  @brief Reads command line in management client
29  *
30  *  This class has one public method which reads a command line
31  *  from a stream. It then interpret that commmand line and calls a suitable
32  *  method in the MgmtSrvr class which executes the command.
33  *
34  *  For command syntax, see the HELP command.
35  */
36 class CommandInterpreter {
37 public:
38   /**
39    *   Constructor
40    *   @param mgmtSrvr: Management server to use when executing commands
41    */
42   CommandInterpreter(const char *, int verbose);
43   ~CommandInterpreter();
44 
45   /**
46    *   Reads one line from the stream, parse the line to find
47    *   a command and then calls a suitable method which executes
48    *   the command.
49    *
50    *   @return true until quit/bye/exit has been typed
51    */
52   int execute(const char *_line, int _try_reconnect=-1, bool interactive=1, int *error= 0);
53 
54 private:
55   void printError();
56   int execute_impl(const char *_line, bool interactive=1);
57 
58   /**
59    *   Analyse the command line, after the first token.
60    *
61    *   @param  processId:           DB process id to send command to or -1 if
62    *                                command will be sent to all DB processes.
63    *   @param  allAfterFirstToken:  What the client gave after the
64    *                                first token on the command line
65    *   @return: 0 if analyseAfterFirstToken succeeds, otherwise -1
66    */
67   int  analyseAfterFirstToken(int processId, char* allAfterFirstTokenCstr);
68 
69   int  executeCommand(Vector<BaseString> &command_list,
70                       unsigned command_pos,
71                       int *node_ids, int no_of_nodes);
72   /**
73    *   Parse the block specification part of the LOG* commands,
74    *   things after LOG*: [BLOCK = {ALL|<blockName>+}]
75    *
76    *   @param  allAfterLog: What the client gave after the second token
77    *                        (LOG*) on the command line
78    *   @param  blocks, OUT: ALL or name of all the blocks
79    *   @return: true if correct syntax, otherwise false
80    */
81   bool parseBlockSpecification(const char* allAfterLog,
82 			       Vector<const char*>& blocks);
83 
84   /**
85    *   A bunch of execute functions: Executes one of the commands
86    *
87    *   @param  processId:   DB process id to send command to
88    *   @param  parameters:  What the client gave after the command name
89    *                        on the command line.
90    *   For example if complete input from user is: "1 LOGLEVEL 22" then the
91    *   parameters argument is the string with everything after LOGLEVEL, in
92    *   this case "22". Each function is responsible to check the parameters
93    *   argument.
94    */
95   int  executeHelp(char* parameters);
96   int  executeShow(char* parameters);
97   int  executePurge(char* parameters);
98   int  executeConnect(char* parameters, bool interactive);
99   int  executeShutdown(char* parameters);
100   void executeRun(char* parameters);
101   void executeInfo(char* parameters);
102   void executeClusterLog(char* parameters);
103 
104 public:
105   int  executeStop(int processId, const char* parameters, bool all);
106   int  executeEnterSingleUser(char* parameters);
107   int  executeExitSingleUser(char* parameters);
108   int  executeStart(int processId, const char* parameters, bool all);
109   int  executeRestart(int processId, const char* parameters, bool all);
110   int  executeLogLevel(int processId, const char* parameters, bool all);
111   int  executeError(int processId, const char* parameters, bool all);
112   int  executeLog(int processId, const char* parameters, bool all);
113   int  executeLogIn(int processId, const char* parameters, bool all);
114   int  executeLogOut(int processId, const char* parameters, bool all);
115   int  executeLogOff(int processId, const char* parameters, bool all);
116   int  executeTestOn(int processId, const char* parameters, bool all);
117   int  executeTestOff(int processId, const char* parameters, bool all);
118   int  executeSet(int processId, const char* parameters, bool all);
119   int  executeGetStat(int processId, const char* parameters, bool all);
120   int  executeStatus(int processId, const char* parameters, bool all);
121   int  executeEventReporting(int processId, const char* parameters, bool all);
122   int  executeDumpState(int processId, const char* parameters, bool all);
123   int  executeStartBackup(char * parameters, bool interactive);
124   int  executeAbortBackup(char * parameters);
125   int  executeStop(Vector<BaseString> &command_list, unsigned command_pos,
126                    int *node_ids, int no_of_nodes);
127   int  executeRestart(Vector<BaseString> &command_list, unsigned command_pos,
128                       int *node_ids, int no_of_nodes);
129 
130   int  executeRep(char* parameters);
131 
132   void executeCpc(char * parameters);
133 
134 public:
135   bool connect(bool interactive);
136   bool disconnect();
137 
138   /**
139    * A execute function definition
140    */
141 public:
142   typedef int (CommandInterpreter::* ExecuteFunction)(int processId,
143 						       const char * param,
144 						       bool all);
145 
146   struct CommandFunctionPair {
147     const char * command;
148     ExecuteFunction executeFunction;
149   };
150 private:
151   /**
152    *
153    */
154   int  executeForAll(const char * cmd,
155 		     ExecuteFunction fun,
156 		     const char * param);
157 
158   NdbMgmHandle m_mgmsrv;
159   NdbMgmHandle m_mgmsrv2;
160   const char *m_constr;
161   bool m_connected;
162   int m_verbose;
163   int try_reconnect;
164   int m_error;
165   struct NdbThread* m_event_thread;
166   NdbMutex *m_print_mutex;
167 };
168 
169 struct event_thread_param {
170   NdbMgmHandle *m;
171   NdbMutex **p;
172 };
173 
174 NdbMutex* print_mutex;
175 
176 /*
177  * Facade object for CommandInterpreter
178  */
179 
180 #include "ndb_mgmclient.hpp"
181 #include "ndb_mgmclient.h"
182 
Ndb_mgmclient(const char * host,int verbose)183 Ndb_mgmclient::Ndb_mgmclient(const char *host,int verbose)
184 {
185   m_cmd= new CommandInterpreter(host,verbose);
186 }
~Ndb_mgmclient()187 Ndb_mgmclient::~Ndb_mgmclient()
188 {
189   delete m_cmd;
190 }
execute(const char * _line,int _try_reconnect,bool interactive,int * error)191 int Ndb_mgmclient::execute(const char *_line, int _try_reconnect, bool interactive, int *error)
192 {
193   return m_cmd->execute(_line,_try_reconnect,interactive, error);
194 }
195 int
disconnect()196 Ndb_mgmclient::disconnect()
197 {
198   return m_cmd->disconnect();
199 }
200 
201 extern "C" {
ndb_mgmclient_handle_create(const char * connect_string)202   Ndb_mgmclient_handle ndb_mgmclient_handle_create(const char *connect_string)
203   {
204     return (Ndb_mgmclient_handle) new Ndb_mgmclient(connect_string);
205   }
ndb_mgmclient_execute(Ndb_mgmclient_handle h,int argc,char ** argv)206   int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, char** argv)
207   {
208     return ((Ndb_mgmclient*)h)->execute(argc, argv, 1);
209   }
ndb_mgmclient_handle_destroy(Ndb_mgmclient_handle h)210   int ndb_mgmclient_handle_destroy(Ndb_mgmclient_handle h)
211   {
212     delete (Ndb_mgmclient*)h;
213     return 0;
214   }
215 }
216 /*
217  * The CommandInterpreter
218  */
219 
220 #include <mgmapi.h>
221 #include <mgmapi_debug.h>
222 #include <version.h>
223 #include <NdbAutoPtr.hpp>
224 #include <NdbOut.hpp>
225 #include <NdbSleep.h>
226 #include <NdbMem.h>
227 #include <EventLogger.hpp>
228 #include <signaldata/SetLogLevelOrd.hpp>
229 #include "MgmtErrorReporter.hpp"
230 #include <Parser.hpp>
231 #include <SocketServer.hpp>
232 #include <util/InputStream.hpp>
233 #include <util/OutputStream.hpp>
234 
execute(int argc,char ** argv,int _try_reconnect,bool interactive,int * error)235 int Ndb_mgmclient::execute(int argc, char** argv, int _try_reconnect, bool interactive, int *error)
236 {
237   if (argc <= 0)
238     return 0;
239   BaseString _line(argv[0]);
240   for (int i= 1; i < argc; i++)
241   {
242     _line.appfmt(" %s", argv[i]);
243   }
244   return m_cmd->execute(_line.c_str(),_try_reconnect, interactive, error);
245 }
246 
247 /*****************************************************************************
248  * HELP
249  *****************************************************************************/
250 static const char* helpText =
251 "---------------------------------------------------------------------------\n"
252 " NDB Cluster -- Management Client -- Help\n"
253 "---------------------------------------------------------------------------\n"
254 "HELP                                   Print help text\n"
255 "HELP COMMAND                           Print detailed help for COMMAND(e.g. SHOW)\n"
256 #ifdef VM_TRACE // DEBUG ONLY
257 "HELP DEBUG                             Help for debug compiled version\n"
258 #endif
259 "SHOW                                   Print information about cluster\n"
260 #if 0
261 "SHOW CONFIG                            Print configuration\n"
262 "SHOW PARAMETERS                        Print configuration parameters\n"
263 #endif
264 "START BACKUP [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
265 "                                       Start backup (default WAIT COMPLETED)\n"
266 "ABORT BACKUP <backup id>               Abort backup\n"
267 "SHUTDOWN                               Shutdown all processes in cluster\n"
268 "CLUSTERLOG ON [<severity>] ...         Enable Cluster logging\n"
269 "CLUSTERLOG OFF [<severity>] ...        Disable Cluster logging\n"
270 "CLUSTERLOG TOGGLE [<severity>] ...     Toggle severity filter on/off\n"
271 "CLUSTERLOG INFO                        Print cluster log information\n"
272 "<id> START                             Start data node (started with -n)\n"
273 "<id> RESTART [-n] [-i] [-a]            Restart data or management server node\n"
274 "<id> STOP [-a]                         Stop data or management server node\n"
275 "ENTER SINGLE USER MODE <id>            Enter single user mode\n"
276 "EXIT SINGLE USER MODE                  Exit single user mode\n"
277 "<id> STATUS                            Print status\n"
278 "<id> CLUSTERLOG {<category>=<level>}+  Set log level for cluster log\n"
279 "PURGE STALE SESSIONS                   Reset reserved nodeid's in the mgmt server\n"
280 "CONNECT [<connectstring>]              Connect to management server (reconnect if already connected)\n"
281 "QUIT                                   Quit management client\n"
282 ;
283 
284 static const char* helpTextShow =
285 "---------------------------------------------------------------------------\n"
286 " NDB Cluster -- Management Client -- Help for SHOW command\n"
287 "---------------------------------------------------------------------------\n"
288 "SHOW Print information about cluster\n\n"
289 "SHOW               Print information about cluster.The status reported is from\n"
290 "                   the perspective of the data nodes. API and Management Server nodes\n"
291 "                   are only reported as connected once the data nodes have started.\n"
292 #if 0
293 "SHOW CONFIG        Print configuration (in initial config file format)\n"
294 "SHOW PARAMETERS    Print information about configuration parameters\n\n"
295 #endif
296 ;
297 
298 static const char* helpTextHelp =
299 "---------------------------------------------------------------------------\n"
300 " NDB Cluster -- Management Client -- Help for HELP command\n"
301 "---------------------------------------------------------------------------\n"
302 "HELP List available commands of NDB Cluster Management Client\n\n"
303 "HELP               List available commands.\n"
304 ;
305 
306 static const char* helpTextBackup =
307 "---------------------------------------------------------------------------\n"
308 " NDB Cluster -- Management Client -- Help for BACKUP command\n"
309 "---------------------------------------------------------------------------\n"
310 "BACKUP  A backup is a snapshot of the database at a given time. \n"
311 "        The backup consists of three main parts:\n\n"
312 "        Metadata: the names and definitions of all database tables. \n"
313 "        Table records: the data actually stored in the database tables \n"
314 "        at the time that the backup was made.\n"
315 "        Transaction log: a sequential record telling how \n"
316 "        and when data was stored in the database.\n\n"
317 "        Backups are stored on each data node in the cluster that \n"
318 "        participates in the backup.\n\n"
319 "        The cluster log records backup related events (such as \n"
320 "        backup started, aborted, finished).\n"
321 ;
322 
323 static const char* helpTextStartBackup =
324 "---------------------------------------------------------------------------\n"
325 " NDB Cluster -- Management Client -- Help for START BACKUP command\n"
326 "---------------------------------------------------------------------------\n"
327 "START BACKUP  Start a cluster backup\n\n"
328 "START BACKUP [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
329 "                   Start a backup for the cluster.\n"
330 "                   Each backup gets an ID number that is reported to the\n"
331 "                   user. This ID number can help you find the backup on the\n"
332 "                   file system, or ABORT BACKUP if you wish to cancel a \n"
333 "                   running backup.\n\n"
334 "                   NOWAIT \n"
335 "                     Start a cluster backup and return immediately.\n"
336 "                     The management client will return control directly\n"
337 "                     to the user without waiting for the backup\n"
338 "                     to have started.\n"
339 "                     The status of the backup is recorded in the Cluster log.\n"
340 "                   WAIT STARTED\n"
341 "                     Start a cluster backup and return until the backup has\n"
342 "                     started. The management client will wait for the backup \n"
343 "                     to have started before returning control to the user.\n"
344 "                   WAIT COMPLETED\n"
345 "                     Start a cluster backup and return until the backup has\n"
346 "                     completed. The management client will wait for the backup\n"
347 "                     to complete before returning control to the user.\n"
348 ;
349 
350 static const char* helpTextAbortBackup =
351 "---------------------------------------------------------------------------\n"
352 " NDB Cluster -- Management Client -- Help for ABORT BACKUP command\n"
353 "---------------------------------------------------------------------------\n"
354 "ABORT BACKUP  Abort a cluster backup\n\n"
355 "ABORT BACKUP <backup id>  \n"
356 "                   Abort a backup that is already in progress.\n"
357 "                   The backup id can be seen in the cluster log or in the\n"
358 "                   output of the START BACKUP command.\n"
359 ;
360 
361 static const char* helpTextShutdown =
362 "---------------------------------------------------------------------------\n"
363 " NDB Cluster -- Management Client -- Help for SHUTDOWN command\n"
364 "---------------------------------------------------------------------------\n"
365 "SHUTDOWN  Shutdown the cluster\n\n"
366 "SHUTDOWN           Shutdown the data nodes and management nodes.\n"
367 "                   MySQL Servers and NDBAPI nodes are currently not \n"
368 "                   shut down by issuing this command.\n"
369 ;
370 
371 static const char* helpTextClusterlogOn =
372 "---------------------------------------------------------------------------\n"
373 " NDB Cluster -- Management Client -- Help for CLUSTERLOG ON command\n"
374 "---------------------------------------------------------------------------\n"
375 "CLUSTERLOG ON  Enable Cluster logging\n\n"
376 "CLUSTERLOG ON [<severity>] ... \n"
377 "                   Turn the cluster log on.\n"
378 "                   It tells management server which severity levels\n"
379 "                   messages will be logged.\n\n"
380 "                   <severity> can be any one of the following values:\n"
381 "                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
382 ;
383 
384 static const char* helpTextClusterlogOff =
385 "---------------------------------------------------------------------------\n"
386 " NDB Cluster -- Management Client -- Help for CLUSTERLOG OFF command\n"
387 "---------------------------------------------------------------------------\n"
388 "CLUSTERLOG OFF  Disable Cluster logging\n\n"
389 "CLUSTERLOG OFF [<severity>] ...  \n"
390 "                   Turn the cluster log off.\n"
391 "                   It tells management server which serverity\n"
392 "                   levels logging will be disabled.\n\n"
393 "                   <severity> can be any one of the following values:\n"
394 "                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
395 ;
396 
397 static const char* helpTextClusterlogToggle =
398 "---------------------------------------------------------------------------\n"
399 " NDB Cluster -- Management Client -- Help for CLUSTERLOG TOGGLE command\n"
400 "---------------------------------------------------------------------------\n"
401 "CLUSTERLOG TOGGLE  Toggle severity filter on/off\n\n"
402 "CLUSTERLOG TOGGLE [<severity>] ...  \n"
403 "                   Toggle serverity filter on/off.\n"
404 "                   If a serverity level is already enabled,then it will\n"
405 "                   be disabled after you use the command,vice versa.\n\n"
406 "                   <severity> can be any one of the following values:\n"
407 "                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
408 ;
409 
410 static const char* helpTextClusterlogInfo =
411 "---------------------------------------------------------------------------\n"
412 " NDB Cluster -- Management Client -- Help for CLUSTERLOG INFO command\n"
413 "---------------------------------------------------------------------------\n"
414 "CLUSTERLOG INFO  Print cluster log information\n\n"
415 "CLUSTERLOG INFO    Display which severity levels have been enabled,\n"
416 "                   see HELP CLUSTERLOG for list of the severity levels.\n"
417 ;
418 
419 static const char* helpTextStart =
420 "---------------------------------------------------------------------------\n"
421 " NDB Cluster -- Management Client -- Help for START command\n"
422 "---------------------------------------------------------------------------\n"
423 "START  Start data node (started with -n)\n\n"
424 "<id> START         Start the data node identified by <id>.\n"
425 "                   Only starts data nodes that have not\n"
426 "                   yet joined the cluster. These are nodes\n"
427 "                   launched or restarted with the -n(--nostart)\n"
428 "                   option.\n\n"
429 "                   It does not launch the ndbd process on a remote\n"
430 "                   machine.\n"
431 ;
432 
433 static const char* helpTextRestart =
434 "---------------------------------------------------------------------------\n"
435 " NDB Cluster -- Management Client -- Help for RESTART command\n"
436 "---------------------------------------------------------------------------\n"
437 "RESTART  Restart data or management server node\n\n"
438 "<id> RESTART [-n] [-i] [-a]\n"
439 "                   Restart the data or management node <id>(or All data nodes).\n\n"
440 "                   -n (--nostart) restarts the node but does not\n"
441 "                   make it join the cluster. Use '<id> START' to\n"
442 "                   join the node to the cluster.\n\n"
443 "                   -i (--initial) perform initial start.\n"
444 "                   This cleans the file system (ndb_<id>_fs)\n"
445 "                   and the node will copy data from another node\n"
446 "                   in the same node group during start up.\n\n"
447 "                   Consult the documentation before using -i.\n\n"
448 "                   INCORRECT USE OF -i WILL CAUSE DATA LOSS!\n"
449 "                   -a Aborts the node, not syncing GCP.\n"
450 ;
451 
452 static const char* helpTextStop =
453 "---------------------------------------------------------------------------\n"
454 " NDB Cluster -- Management Client -- Help for STOP command\n"
455 "---------------------------------------------------------------------------\n"
456 "STOP  Stop data or management server node\n\n"
457 "<id> STOP [-a]     Stop the data or management server node <id>.\n\n"
458 "                   ALL STOP will just stop all data nodes.\n\n"
459 "                   If you desire to also shut down management servers,\n"
460 "                   use SHUTDOWN instead.\n"
461 "                   -a Aborts the node, not syncing GCP.\n"
462 ;
463 
464 static const char* helpTextEnterSingleUserMode =
465 "---------------------------------------------------------------------------\n"
466 " NDB Cluster -- Management Client -- Help for ENTER SINGLE USER MODE command\n"
467 "---------------------------------------------------------------------------\n"
468 "ENTER SINGLE USER MODE  Enter single user mode\n\n"
469 "ENTER SINGLE USER MODE <id> \n"
470 "                   Enters single-user mode, whereby only the MySQL Server or NDBAPI\n"
471 "                   node identified by <id> is allowed to access the database. \n"
472 ;
473 
474 static const char* helpTextExitSingleUserMode =
475 "---------------------------------------------------------------------------\n"
476 " NDB Cluster -- Management Client -- Help for EXIT SINGLE USER MODE command\n"
477 "---------------------------------------------------------------------------\n"
478 "EXIT SINGLE USER MODE  Exit single user mode\n\n"
479 "EXIT SINGLE USER MODE \n"
480 "                   Exits single-user mode, allowing all SQL nodes \n"
481 "                   (that is, all running mysqld processes) to access the database. \n"
482 ;
483 
484 static const char* helpTextStatus =
485 "---------------------------------------------------------------------------\n"
486 " NDB Cluster -- Management Client -- Help for STATUS command\n"
487 "---------------------------------------------------------------------------\n"
488 "STATUS  Print status\n\n"
489 "<id> STATUS        Displays status information for the data node <id>\n"
490 "                   or for All data nodes. \n\n"
491 "                   e.g.\n"
492 "                      ALL STATUS\n"
493 "                      1 STATUS\n\n"
494 "                   When a node is starting, the start phase will be\n"
495 "                   listed.\n\n"
496 "                   Start Phase   Meaning\n"
497 "                   1             Clear the cluster file system(ndb_<id>_fs). \n"
498 "                                 This stage occurs only when the --initial option \n"
499 "                                 has been specified.\n"
500 "                   2             This stage sets up Cluster connections, establishes \n"
501 "                                 inter-node communications and starts Cluster heartbeats.\n"
502 "                   3             The arbitrator node is elected.\n"
503 "                   4             Initializes a number of internal cluster variables.\n"
504 "                   5             For an initial start or initial node restart,\n"
505 "                                 the redo log files are created.\n"
506 "                   6             If this is an initial start, create internal system tables.\n"
507 "                   7             Update internal variables. \n"
508 "                   8             In a system restart, rebuild all indexes.\n"
509 "                   9             Update internal variables. \n"
510 "                   10            The node can be connected by APIs and can receive events.\n"
511 "                   11            At this point,event delivery is handed over to\n"
512 "                                 the node joining the cluster.\n"
513 "(see manual for more information)\n"
514 ;
515 
516 static const char* helpTextClusterlog =
517 "---------------------------------------------------------------------------\n"
518 " NDB Cluster -- Management Client -- Help for CLUSTERLOG command\n"
519 "---------------------------------------------------------------------------\n"
520 "CLUSTERLOG  Set log level for cluster log\n\n"
521 " <id> CLUSTERLOG {<category>=<level>}+  \n"
522 "                   Logs <category> events with priority less than \n"
523 "                   or equal to <level> in the cluster log.\n\n"
524 "                   <category> can be any one of the following values:\n"
525 "                   STARTUP, SHUTDOWN, STATISTICS, CHECKPOINT, NODERESTART,\n"
526 "                   CONNECTION, ERROR, INFO, CONGESTION, DEBUG, or BACKUP. \n\n"
527 "                   <level> is represented by one of the numbers \n"
528 "                   from 1 to 15 inclusive, where 1 indicates 'most important' \n"
529 "                   and 15 'least important'.\n\n"
530 "                   <severity> can be any one of the following values:\n"
531 "                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
532 ;
533 
534 
535 static const char* helpTextPurgeStaleSessions =
536 "---------------------------------------------------------------------------\n"
537 " NDB Cluster -- Management Client -- Help for PURGE STALE SESSIONS command\n"
538 "---------------------------------------------------------------------------\n"
539 "PURGE STALE SESSIONS  Reset reserved nodeid's in the mgmt server\n\n"
540 "PURGE STALE SESSIONS \n"
541 "                   Running this statement forces all reserved \n"
542 "                   node IDs to be checked; any that are not \n"
543 "                   being used by nodes acutally connected to \n"
544 "                   the cluster are then freed.\n\n"
545 "                   This command is not normally needed, but may be\n"
546 "                   required in some situations where failed nodes \n"
547 "                   cannot rejoin the cluster due to failing to\n"
548 "                   allocate a node id.\n"
549 ;
550 
551 static const char* helpTextConnect =
552 "---------------------------------------------------------------------------\n"
553 " NDB Cluster -- Management Client -- Help for CONNECT command\n"
554 "---------------------------------------------------------------------------\n"
555 "CONNECT  Connect to management server (reconnect if already connected)\n\n"
556 "CONNECT [<connectstring>] \n"
557 "                   Connect to management server.\n"
558 "                   The optional parameter connectstring specifies the \n"
559 "                   connect string to user.\n\n"
560 "                   A connect string may be:\n"
561 "                       mgm-server\n"
562 "                       mgm-server:port\n"
563 "                       mgm1:port,mgm2:port\n"
564 "                   With multiple management servers comma separated.\n"
565 "                   The management client with try to connect to the \n"
566 "                   management servers in the order they are listed.\n\n"
567 "                   If no connect string is specified, the default \n"
568 "                   is used. \n"
569 ;
570 
571 static const char* helpTextQuit =
572 "---------------------------------------------------------------------------\n"
573 " NDB Cluster -- Management Client -- Help for QUIT command\n"
574 "---------------------------------------------------------------------------\n"
575 "QUIT  Quit management client\n\n"
576 "QUIT               Terminates the management client. \n"
577 ;
578 
579 
580 #ifdef VM_TRACE // DEBUG ONLY
581 static const char* helpTextDebug =
582 "---------------------------------------------------------------------------\n"
583 " NDB Cluster -- Management Client -- Help for Debugging (Internal use only)\n"
584 "---------------------------------------------------------------------------\n"
585 "SHOW PROPERTIES                       Print config properties object\n"
586 "<id> LOGLEVEL {<category>=<level>}+   Set log level\n"
587 #ifdef ERROR_INSERT
588 "<id> ERROR <errorNo>                  Inject error into NDB node\n"
589 #endif
590 "<id> LOG [BLOCK = {ALL|<block>+}]     Set logging on in & out signals\n"
591 "<id> LOGIN [BLOCK = {ALL|<block>+}]   Set logging on in signals\n"
592 "<id> LOGOUT [BLOCK = {ALL|<block>+}]  Set logging on out signals\n"
593 "<id> LOGOFF [BLOCK = {ALL|<block>+}]  Unset signal logging\n"
594 "<id> TESTON                           Start signal logging\n"
595 "<id> TESTOFF                          Stop signal logging\n"
596 "<id> SET <configParamName> <value>    Update configuration variable\n"
597 "<id> DUMP <arg>                       Dump system state to cluster.log\n"
598 "<id> GETSTAT                          Print statistics\n"
599 "\n"
600 "<id>       = ALL | Any database node id\n"
601 ;
602 #endif
603 
604 struct st_cmd_help {
605   const char *cmd;
606   const char * help;
607 }help_items[]={
608   {"SHOW", helpTextShow},
609   {"HELP", helpTextHelp},
610   {"BACKUP", helpTextBackup},
611   {"START BACKUP", helpTextStartBackup},
612   {"START BACKUP NOWAIT", helpTextStartBackup},
613   {"START BACKUP WAIT STARTED", helpTextStartBackup},
614   {"START BACKUP WAIT", helpTextStartBackup},
615   {"START BACKUP WAIT COMPLETED", helpTextStartBackup},
616   {"ABORT BACKUP", helpTextAbortBackup},
617   {"SHUTDOWN", helpTextShutdown},
618   {"CLUSTERLOG ON", helpTextClusterlogOn},
619   {"CLUSTERLOG OFF", helpTextClusterlogOff},
620   {"CLUSTERLOG TOGGLE", helpTextClusterlogToggle},
621   {"CLUSTERLOG INFO", helpTextClusterlogInfo},
622   {"START", helpTextStart},
623   {"RESTART", helpTextRestart},
624   {"STOP", helpTextStop},
625   {"ENTER SINGLE USER MODE", helpTextEnterSingleUserMode},
626   {"EXIT SINGLE USER MODE", helpTextExitSingleUserMode},
627   {"STATUS", helpTextStatus},
628   {"CLUSTERLOG", helpTextClusterlog},
629   {"PURGE STALE SESSIONS", helpTextPurgeStaleSessions},
630   {"CONNECT", helpTextConnect},
631   {"QUIT", helpTextQuit},
632 #ifdef VM_TRACE // DEBUG ONLY
633   {"DEBUG", helpTextDebug},
634 #endif //VM_TRACE
635   {NULL, NULL}
636 };
637 
638 static bool
convert(const char * s,int & val)639 convert(const char* s, int& val) {
640 
641   if (s == NULL)
642     return false;
643 
644   if (strlen(s) == 0)
645     return false;
646 
647   errno = 0;
648   char* p;
649   long v = strtol(s, &p, 10);
650   if (errno != 0)
651     return false;
652 
653   if (p != &s[strlen(s)])
654     return false;
655 
656   val = v;
657   return true;
658 }
659 
660 /*
661  * Constructor
662  */
CommandInterpreter(const char * _host,int verbose)663 CommandInterpreter::CommandInterpreter(const char *_host,int verbose)
664   : m_verbose(verbose)
665 {
666   m_constr= _host;
667   m_connected= false;
668   m_event_thread= NULL;
669   try_reconnect = 0;
670   m_print_mutex= NdbMutex_Create();
671 }
672 
673 /*
674  * Destructor
675  */
~CommandInterpreter()676 CommandInterpreter::~CommandInterpreter()
677 {
678   disconnect();
679   NdbMutex_Destroy(m_print_mutex);
680 }
681 
682 static bool
emptyString(const char * s)683 emptyString(const char* s)
684 {
685   if (s == NULL) {
686     return true;
687   }
688 
689   for (unsigned int i = 0; i < strlen(s); ++i) {
690     if (! isspace(s[i])) {
691       return false;
692     }
693   }
694 
695   return true;
696 }
697 
698 void
printError()699 CommandInterpreter::printError()
700 {
701   ndbout_c("* %5d: %s",
702 	   ndb_mgm_get_latest_error(m_mgmsrv),
703 	   ndb_mgm_get_latest_error_msg(m_mgmsrv));
704   ndbout_c("*        %s", ndb_mgm_get_latest_error_desc(m_mgmsrv));
705   if (ndb_mgm_check_connection(m_mgmsrv))
706   {
707     disconnect();
708   }
709 }
710 
711 /*
712  * print log event from mgmsrv to console screen
713  */
714 #define make_uint64(a,b) (((Uint64)(a)) + (((Uint64)(b)) << 32))
715 #define Q64(a) make_uint64(event->EVENT.a ## _lo, event->EVENT.a ## _hi)
716 #define R event->source_nodeid
717 #define Q(a) event->EVENT.a
718 #define QVERSION getMajor(Q(version)), getMinor(Q(version)), getBuild(Q(version))
719 #define NDB_LE_(a) NDB_LE_ ## a
720 static void
printLogEvent(struct ndb_logevent * event)721 printLogEvent(struct ndb_logevent* event)
722 {
723   switch (event->type) {
724     /**
725      * NDB_MGM_EVENT_CATEGORY_BACKUP
726      */
727 #undef  EVENT
728 #define EVENT BackupStarted
729   case NDB_LE_BackupStarted:
730       ndbout_c("Node %u: Backup %d started from node %d",
731                R, Q(backup_id), Q(starting_node));
732       break;
733 #undef  EVENT
734 #define EVENT BackupFailedToStart
735     case NDB_LE_BackupFailedToStart:
736       ndbout_c("Node %u: Backup request from %d failed to start. Error: %d",
737                R, Q(starting_node), Q(error));
738       break;
739 #undef  EVENT
740 #define EVENT BackupCompleted
741     case NDB_LE_BackupCompleted:
742       ndbout_c("Node %u: Backup %u started from node %u completed\n"
743                " StartGCP: %u StopGCP: %u\n"
744                " #Records: %u #LogRecords: %u\n"
745                " Data: %u bytes Log: %u bytes", R,
746                Q(backup_id), Q(starting_node),
747                Q(start_gci), Q(stop_gci),
748                Q(n_records), Q(n_log_records),
749                Q(n_bytes),   Q(n_log_bytes));
750       break;
751 #undef  EVENT
752 #define EVENT BackupAborted
753     case NDB_LE_BackupAborted:
754       ndbout_c("Node %u: Backup %d started from %d has been aborted. Error: %d",
755                R, Q(backup_id), Q(starting_node), Q(error));
756       break;
757     /**
758      * NDB_MGM_EVENT_CATEGORY_STARTUP
759      */
760 #undef  EVENT
761 #define EVENT NDBStartStarted
762     case NDB_LE_NDBStartStarted:
763       ndbout_c("Node %u: Start initiated (version %d.%d.%d)",
764                R, QVERSION);
765       break;
766 #undef  EVENT
767 #define EVENT NDBStartCompleted
768     case NDB_LE_NDBStartCompleted:
769       ndbout_c("Node %u: Started (version %d.%d.%d)",
770                R, QVERSION);
771       break;
772 #undef  EVENT
773 #define EVENT NDBStopStarted
774     case NDB_LE_NDBStopStarted:
775       ndbout_c("Node %u: %s shutdown initiated", R,
776                (Q(stoptype) == 1 ? "Cluster" : "Node"));
777       break;
778 #undef  EVENT
779 #define EVENT NDBStopCompleted
780     case NDB_LE_NDBStopCompleted:
781       {
782         BaseString action_str("");
783         BaseString signum_str("");
784         getRestartAction(Q(action), action_str);
785         if (Q(signum))
786           signum_str.appfmt(" Initiated by signal %d.",
787                             Q(signum));
788         ndbout_c("Node %u: Node shutdown completed%s.%s",
789                  R, action_str.c_str(), signum_str.c_str());
790       }
791       break;
792 #undef  EVENT
793 #define EVENT NDBStopForced
794     case NDB_LE_NDBStopForced:
795       {
796         BaseString action_str("");
797         BaseString reason_str("");
798         BaseString sphase_str("");
799         int signum = Q(signum);
800         int error = Q(error);
801         int sphase = Q(sphase);
802         int extra = Q(extra);
803         getRestartAction(Q(action), action_str);
804         if (signum)
805           reason_str.appfmt(" Initiated by signal %d.", signum);
806         if (error)
807         {
808           ndbd_exit_classification cl;
809           ndbd_exit_status st;
810           const char *msg = ndbd_exit_message(error, &cl);
811           const char *cl_msg = ndbd_exit_classification_message(cl, &st);
812           const char *st_msg = ndbd_exit_status_message(st);
813           reason_str.appfmt(" Caused by error %d: \'%s(%s). %s\'.",
814                             error, msg, cl_msg, st_msg);
815           if (extra != 0)
816             reason_str.appfmt(" (extra info %d)", extra);
817         }
818         if (sphase < 255)
819           sphase_str.appfmt(" Occured during startphase %u.", sphase);
820         ndbout_c("Node %u: Forced node shutdown completed%s.%s%s",
821                  R, action_str.c_str(), sphase_str.c_str(),
822                  reason_str.c_str());
823       }
824       break;
825 #undef  EVENT
826 #define EVENT StopAborted
827     case NDB_LE_NDBStopAborted:
828       ndbout_c("Node %u: Node shutdown aborted", R);
829       break;
830     /**
831      * default nothing to print
832      */
833     default:
834       break;
835   }
836 }
837 
838 //*****************************************************************************
839 //*****************************************************************************
840 
841 static int do_event_thread;
842 static void*
event_thread_run(void * p)843 event_thread_run(void* p)
844 {
845   DBUG_ENTER("event_thread_run");
846 
847   struct event_thread_param param= *(struct event_thread_param*)p;
848   NdbMgmHandle handle= *(param.m);
849   NdbMutex* printmutex= *(param.p);
850 
851   int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
852 		   1, NDB_MGM_EVENT_CATEGORY_STARTUP,
853 		   0 };
854 
855   NdbLogEventHandle log_handle= NULL;
856   struct ndb_logevent log_event;
857 
858   log_handle= ndb_mgm_create_logevent_handle(handle, filter);
859   if (log_handle)
860   {
861     do_event_thread= 1;
862     do {
863       int res= ndb_logevent_get_next(log_handle, &log_event, 2000);
864       if (res > 0)
865       {
866         Guard g(printmutex);
867         printLogEvent(&log_event);
868       }
869       else if (res < 0)
870         break;
871     } while(do_event_thread);
872     ndb_mgm_destroy_logevent_handle(&log_handle);
873   }
874   else
875   {
876     do_event_thread= -1;
877   }
878 
879   DBUG_RETURN(NULL);
880 }
881 
882 bool
connect(bool interactive)883 CommandInterpreter::connect(bool interactive)
884 {
885   DBUG_ENTER("CommandInterpreter::connect");
886 
887   if(m_connected)
888     DBUG_RETURN(m_connected);
889 
890   m_mgmsrv = ndb_mgm_create_handle();
891   if(m_mgmsrv == NULL) {
892     ndbout_c("Cannot create handle to management server.");
893     exit(-1);
894   }
895   if (interactive) {
896     m_mgmsrv2 = ndb_mgm_create_handle();
897     if(m_mgmsrv2 == NULL) {
898       ndbout_c("Cannot create 2:nd handle to management server.");
899       exit(-1);
900     }
901   }
902 
903   if (ndb_mgm_set_connectstring(m_mgmsrv, m_constr))
904   {
905     printError();
906     exit(-1);
907   }
908 
909   if(ndb_mgm_connect(m_mgmsrv, try_reconnect-1, 5, 1))
910     DBUG_RETURN(m_connected); // couldn't connect, always false
911 
912   const char *host= ndb_mgm_get_connected_host(m_mgmsrv);
913   unsigned port= ndb_mgm_get_connected_port(m_mgmsrv);
914   if (interactive) {
915     BaseString constr;
916     constr.assfmt("%s:%d",host,port);
917     if(!ndb_mgm_set_connectstring(m_mgmsrv2, constr.c_str()) &&
918        !ndb_mgm_connect(m_mgmsrv2, try_reconnect-1, 5, 1))
919     {
920       DBUG_PRINT("info",("2:ndb connected to Management Server ok at: %s:%d",
921                          host, port));
922       assert(m_event_thread == NULL);
923       assert(do_event_thread == 0);
924       do_event_thread= 0;
925       struct event_thread_param p;
926       p.m= &m_mgmsrv2;
927       p.p= &m_print_mutex;
928       m_event_thread = NdbThread_Create(event_thread_run,
929                                         (void**)&p,
930                                         32768,
931                                         "CommandInterpreted_event_thread",
932                                         NDB_THREAD_PRIO_LOW);
933       if (m_event_thread)
934       {
935         DBUG_PRINT("info",("Thread created ok, waiting for started..."));
936         int iter= 1000; // try for 30 seconds
937         while(do_event_thread == 0 &&
938               iter-- > 0)
939           NdbSleep_MilliSleep(30);
940       }
941       if (m_event_thread == NULL ||
942           do_event_thread == 0 ||
943           do_event_thread == -1)
944       {
945         DBUG_PRINT("info",("Warning, event thread startup failed, "
946                            "degraded printouts as result, errno=%d",
947                            errno));
948         printf("Warning, event thread startup failed, "
949                "degraded printouts as result, errno=%d\n", errno);
950         do_event_thread= 0;
951         if (m_event_thread)
952         {
953           void *res;
954           NdbThread_WaitFor(m_event_thread, &res);
955           NdbThread_Destroy(&m_event_thread);
956         }
957         ndb_mgm_disconnect(m_mgmsrv2);
958       }
959     }
960     else
961     {
962       DBUG_PRINT("warning",
963                  ("Could not do 2:nd connect to mgmtserver for event listening"));
964       DBUG_PRINT("info", ("code: %d, msg: %s",
965                           ndb_mgm_get_latest_error(m_mgmsrv2),
966                           ndb_mgm_get_latest_error_msg(m_mgmsrv2)));
967       printf("Warning, event connect failed, degraded printouts as result\n");
968       printf("code: %d, msg: %s\n",
969              ndb_mgm_get_latest_error(m_mgmsrv2),
970              ndb_mgm_get_latest_error_msg(m_mgmsrv2));
971     }
972   }
973   m_connected= true;
974   DBUG_PRINT("info",("Connected to Management Server at: %s:%d", host, port));
975   if (m_verbose)
976   {
977     printf("Connected to Management Server at: %s:%d\n",
978            host, port);
979   }
980 
981   DBUG_RETURN(m_connected);
982 }
983 
984 bool
disconnect()985 CommandInterpreter::disconnect()
986 {
987   DBUG_ENTER("CommandInterpreter::disconnect");
988 
989   if (m_event_thread) {
990     void *res;
991     do_event_thread= 0;
992     NdbThread_WaitFor(m_event_thread, &res);
993     NdbThread_Destroy(&m_event_thread);
994     m_event_thread= NULL;
995     ndb_mgm_destroy_handle(&m_mgmsrv2);
996   }
997   if (m_connected)
998   {
999     ndb_mgm_destroy_handle(&m_mgmsrv);
1000     m_connected= false;
1001   }
1002   DBUG_RETURN(true);
1003 }
1004 
1005 //*****************************************************************************
1006 //*****************************************************************************
1007 
1008 int
execute(const char * _line,int _try_reconnect,bool interactive,int * error)1009 CommandInterpreter::execute(const char *_line, int _try_reconnect,
1010 			    bool interactive, int *error)
1011 {
1012   if (_try_reconnect >= 0)
1013     try_reconnect=_try_reconnect;
1014   int result= execute_impl(_line, interactive);
1015   if (error)
1016     *error= m_error;
1017 
1018   return result;
1019 }
1020 
1021 static void
invalid_command(const char * cmd)1022 invalid_command(const char *cmd)
1023 {
1024   ndbout << "Invalid command: " << cmd << endl;
1025   ndbout << "Type HELP for help." << endl << endl;
1026 }
1027 
1028 int
execute_impl(const char * _line,bool interactive)1029 CommandInterpreter::execute_impl(const char *_line, bool interactive)
1030 {
1031   DBUG_ENTER("CommandInterpreter::execute_impl");
1032   DBUG_PRINT("enter",("line=\"%s\"",_line));
1033   m_error= 0;
1034 
1035   char * line;
1036   if(_line == NULL) {
1037     m_error = -1;
1038     DBUG_RETURN(false);
1039   }
1040   line = my_strdup(_line,MYF(MY_WME));
1041   My_auto_ptr<char> ptr(line);
1042 
1043   int do_continue;
1044   do {
1045     do_continue= 0;
1046     BaseString::trim(line," \t");
1047     if (line[0] == 0 ||
1048 	line[0] == '#')
1049     {
1050       DBUG_RETURN(true);
1051     }
1052     // for mysql client compatability remove trailing ';'
1053     {
1054       unsigned last= strlen(line)-1;
1055       if (line[last] == ';')
1056       {
1057 	line[last]= 0;
1058 	do_continue= 1;
1059       }
1060     }
1061   } while (do_continue);
1062   // if there is anything in the line proceed
1063   Vector<BaseString> command_list;
1064   {
1065     BaseString tmp(line);
1066     tmp.split(command_list);
1067     for (unsigned i= 0; i < command_list.size();)
1068       command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
1069   }
1070   char* firstToken = strtok(line, " ");
1071   char* allAfterFirstToken = strtok(NULL, "");
1072 
1073   if (strcasecmp(firstToken, "HELP") == 0 ||
1074       strcasecmp(firstToken, "?") == 0) {
1075     m_error = executeHelp(allAfterFirstToken);
1076     DBUG_RETURN(true);
1077   }
1078   else if (strcasecmp(firstToken, "CONNECT") == 0) {
1079     m_error = executeConnect(allAfterFirstToken, interactive);
1080     DBUG_RETURN(true);
1081   }
1082   else if (strcasecmp(firstToken, "SLEEP") == 0) {
1083     if (allAfterFirstToken)
1084       if (sleep(atoi(allAfterFirstToken)) != 0 )
1085         m_error = -1;
1086     DBUG_RETURN(true);
1087   }
1088   else if((strcasecmp(firstToken, "QUIT") == 0 ||
1089 	  strcasecmp(firstToken, "EXIT") == 0 ||
1090 	  strcasecmp(firstToken, "BYE") == 0) &&
1091 	  allAfterFirstToken == NULL){
1092     DBUG_RETURN(false);
1093   }
1094 
1095   if (!connect(interactive)){
1096     m_error = -1;
1097     DBUG_RETURN(true);
1098   }
1099 
1100   if (ndb_mgm_check_connection(m_mgmsrv))
1101   {
1102     disconnect();
1103     connect(interactive);
1104   }
1105 
1106   if (strcasecmp(firstToken, "SHOW") == 0) {
1107     Guard g(m_print_mutex);
1108     m_error = executeShow(allAfterFirstToken);
1109     DBUG_RETURN(true);
1110   }
1111   else if (strcasecmp(firstToken, "SHUTDOWN") == 0) {
1112     m_error= executeShutdown(allAfterFirstToken);
1113     DBUG_RETURN(true);
1114   }
1115   else if (strcasecmp(firstToken, "CLUSTERLOG") == 0){
1116     executeClusterLog(allAfterFirstToken);
1117     DBUG_RETURN(true);
1118   }
1119   else if(strcasecmp(firstToken, "START") == 0 &&
1120 	  allAfterFirstToken != NULL &&
1121 	  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1122     m_error= executeStartBackup(allAfterFirstToken, interactive);
1123     DBUG_RETURN(true);
1124   }
1125   else if(strcasecmp(firstToken, "ABORT") == 0 &&
1126 	  allAfterFirstToken != NULL &&
1127 	  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1128     m_error = executeAbortBackup(allAfterFirstToken);
1129     DBUG_RETURN(true);
1130   }
1131   else if (strcasecmp(firstToken, "PURGE") == 0) {
1132     m_error = executePurge(allAfterFirstToken);
1133     DBUG_RETURN(true);
1134   }
1135   else if(strcasecmp(firstToken, "ENTER") == 0 &&
1136 	  allAfterFirstToken != NULL &&
1137 	  allAfterFirstToken != NULL &&
1138 	  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1139 		  sizeof("SINGLE USER MODE") - 1) == 0){
1140     m_error = executeEnterSingleUser(allAfterFirstToken);
1141     DBUG_RETURN(true);
1142   }
1143   else if(strcasecmp(firstToken, "EXIT") == 0 &&
1144 	  allAfterFirstToken != NULL &&
1145 	  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1146 		  sizeof("SINGLE USER MODE") - 1) == 0){
1147     m_error = executeExitSingleUser(allAfterFirstToken);
1148     DBUG_RETURN(true);
1149   }
1150   else if (strcasecmp(firstToken, "ALL") == 0) {
1151     m_error = analyseAfterFirstToken(-1, allAfterFirstToken);
1152   } else {
1153     /**
1154      * First tokens should be digits, node ID's
1155      */
1156     int node_ids[MAX_NODES];
1157     unsigned pos;
1158     for (pos= 0; pos < command_list.size(); pos++)
1159     {
1160       int node_id;
1161       if (convert(command_list[pos].c_str(), node_id))
1162       {
1163         if (node_id <= 0 || node_id > MAX_NODES) {
1164           ndbout << "Invalid node ID: " << command_list[pos].c_str()
1165                  << "." << endl;
1166           DBUG_RETURN(true);
1167         }
1168         node_ids[pos]= node_id;
1169         continue;
1170       }
1171       break;
1172     }
1173     int no_of_nodes= pos;
1174     if (no_of_nodes == 0)
1175     {
1176       /* No digit found */
1177       invalid_command(_line);
1178       m_error = -1;
1179       DBUG_RETURN(true);
1180     }
1181     if (pos == command_list.size())
1182     {
1183       /* No command found */
1184       invalid_command(_line);
1185       m_error = -1;
1186       DBUG_RETURN(true);
1187     }
1188     if (no_of_nodes == 1)
1189     {
1190       m_error = analyseAfterFirstToken(node_ids[0], allAfterFirstToken);
1191       DBUG_RETURN(true);
1192     }
1193     m_error = executeCommand(command_list, pos, node_ids, no_of_nodes);
1194     DBUG_RETURN(true);
1195   }
1196   DBUG_RETURN(true);
1197 }
1198 
1199 
1200 /**
1201  * List of commands used as second command argument
1202  */
1203 static const CommandInterpreter::CommandFunctionPair commands[] = {
1204   { "START", &CommandInterpreter::executeStart }
1205   ,{ "RESTART", &CommandInterpreter::executeRestart }
1206   ,{ "STOP", &CommandInterpreter::executeStop }
1207   ,{ "STATUS", &CommandInterpreter::executeStatus }
1208   ,{ "LOGLEVEL", &CommandInterpreter::executeLogLevel }
1209   ,{ "CLUSTERLOG", &CommandInterpreter::executeEventReporting }
1210 #ifdef ERROR_INSERT
1211   ,{ "ERROR", &CommandInterpreter::executeError }
1212 #endif
1213   ,{ "LOG", &CommandInterpreter::executeLog }
1214   ,{ "LOGIN", &CommandInterpreter::executeLogIn }
1215   ,{ "LOGOUT", &CommandInterpreter::executeLogOut }
1216   ,{ "LOGOFF", &CommandInterpreter::executeLogOff }
1217   ,{ "TESTON", &CommandInterpreter::executeTestOn }
1218   ,{ "TESTOFF", &CommandInterpreter::executeTestOff }
1219   ,{ "SET", &CommandInterpreter::executeSet }
1220   ,{ "GETSTAT", &CommandInterpreter::executeGetStat }
1221   ,{ "DUMP", &CommandInterpreter::executeDumpState }
1222 };
1223 
1224 
1225 //*****************************************************************************
1226 //*****************************************************************************
1227 int
analyseAfterFirstToken(int processId,char * allAfterFirstToken)1228 CommandInterpreter::analyseAfterFirstToken(int processId,
1229 					   char* allAfterFirstToken) {
1230 
1231   int retval = 0;
1232   if (emptyString(allAfterFirstToken)) {
1233     ndbout << "Expected a command after "
1234 	   << ((processId == -1) ? "ALL." : "node ID.") << endl;
1235     return -1;
1236   }
1237 
1238   char* secondToken = strtok(allAfterFirstToken, " ");
1239   char* allAfterSecondToken = strtok(NULL, "\0");
1240 
1241   const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
1242   ExecuteFunction fun = 0;
1243   const char * command = 0;
1244   for(int i = 0; i<tmpSize; i++){
1245     if(strcasecmp(secondToken, commands[i].command) == 0){
1246       fun = commands[i].executeFunction;
1247       command = commands[i].command;
1248       break;
1249     }
1250   }
1251 
1252   if(fun == 0){
1253     invalid_command(secondToken);
1254     return -1;
1255   }
1256 
1257   if(processId == -1){
1258     retval = executeForAll(command, fun, allAfterSecondToken);
1259   } else {
1260     retval = (this->*fun)(processId, allAfterSecondToken, false);
1261   }
1262   ndbout << endl;
1263   return retval;
1264 }
1265 
1266 int
executeCommand(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)1267 CommandInterpreter::executeCommand(Vector<BaseString> &command_list,
1268                                    unsigned command_pos,
1269                                    int *node_ids, int no_of_nodes)
1270 {
1271   const char *cmd= command_list[command_pos].c_str();
1272   int retval = 0;
1273 
1274   if (strcasecmp("STOP", cmd) == 0)
1275   {
1276     retval = executeStop(command_list, command_pos+1, node_ids, no_of_nodes);
1277     return retval;
1278   }
1279   if (strcasecmp("RESTART", cmd) == 0)
1280   {
1281     retval = executeRestart(command_list, command_pos+1, node_ids, no_of_nodes);
1282     return retval;
1283   }
1284   ndbout_c("Invalid command: '%s' after multi node id list. "
1285            "Expected STOP or RESTART.", cmd);
1286   return -1;
1287 }
1288 
1289 /**
1290  * Get next nodeid larger than the give node_id. node_id will be
1291  * set to the next node_id in the list. node_id should be set
1292  * to 0 (zero) on the first call.
1293  *
1294  * @param handle the NDB management handle
1295  * @param node_id last node_id retreived, 0 at first call
1296  * @param type type of node to look for
1297  * @return 1 if a node was found, 0 if no more node exist
1298  */
1299 static
1300 int
get_next_nodeid(struct ndb_mgm_cluster_state * cl,int * node_id,enum ndb_mgm_node_type type)1301 get_next_nodeid(struct ndb_mgm_cluster_state *cl,
1302 		int *node_id,
1303 		enum ndb_mgm_node_type type)
1304 {
1305   int i;
1306 
1307   if(cl == NULL)
1308     return 0;
1309 
1310   i=0;
1311   while((i < cl->no_of_nodes)) {
1312     if((*node_id < cl->node_states[i].node_id) &&
1313        (cl->node_states[i].node_type == type)) {
1314 
1315       if(i >= cl->no_of_nodes)
1316 	return 0;
1317 
1318       *node_id = cl->node_states[i].node_id;
1319       return 1;
1320     }
1321     i++;
1322   }
1323 
1324   return 0;
1325 }
1326 
1327 int
executeForAll(const char * cmd,ExecuteFunction fun,const char * allAfterSecondToken)1328 CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun,
1329 				  const char * allAfterSecondToken)
1330 {
1331   int nodeId = 0;
1332   int retval = 0;
1333 
1334   if(strcasecmp(cmd, "STOP") == 0) {
1335     ndbout_c("Executing STOP on all nodes.");
1336     retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1337   } else if(strcasecmp(cmd, "RESTART") == 0) {
1338     ndbout_c("Executing RESTART on all nodes.");
1339     ndbout_c("Starting shutdown. This may take a while. Please wait...");
1340     retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1341     ndbout_c("Trying to start all nodes of system.");
1342     ndbout_c("Use ALL STATUS to see the system start-up phases.");
1343   } else {
1344     Guard g(m_print_mutex);
1345     struct ndb_mgm_cluster_state *cl= ndb_mgm_get_status(m_mgmsrv);
1346     if(cl == 0){
1347       ndbout_c("Unable get status from management server");
1348       printError();
1349       return -1;
1350     }
1351     NdbAutoPtr<char> ap1((char*)cl);
1352     while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB))
1353       retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1354   }
1355   return retval;
1356 }
1357 
1358 //*****************************************************************************
1359 //*****************************************************************************
1360 bool
parseBlockSpecification(const char * allAfterLog,Vector<const char * > & blocks)1361 CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
1362 					    Vector<const char*>& blocks)
1363 {
1364   // Parse: [BLOCK = {ALL|<blockName>+}]
1365 
1366   if (emptyString(allAfterLog)) {
1367     return true;
1368   }
1369 
1370   // Copy allAfterLog since strtok will modify it
1371   char* newAllAfterLog = my_strdup(allAfterLog,MYF(MY_WME));
1372   My_auto_ptr<char> ap1(newAllAfterLog);
1373   char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
1374   for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
1375     firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
1376   }
1377 
1378   if (strcasecmp(firstTokenAfterLog, "BLOCK") != 0) {
1379     ndbout << "Unexpected value: " << firstTokenAfterLog
1380 	   << ". Expected BLOCK." << endl;
1381     return false;
1382   }
1383 
1384   char* allAfterFirstToken = strtok(NULL, "\0");
1385   if (emptyString(allAfterFirstToken)) {
1386     ndbout << "Expected =." << endl;
1387     return false;
1388   }
1389 
1390   char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
1391   if (strcasecmp(secondTokenAfterLog, "=") != 0) {
1392     ndbout << "Unexpected value: " << secondTokenAfterLog
1393 	   << ". Expected =." << endl;
1394     return false;
1395   }
1396 
1397   char* blockName = strtok(NULL, " ");
1398   bool all = false;
1399   if (blockName != NULL && (strcasecmp(blockName, "ALL") == 0)) {
1400     all = true;
1401   }
1402   while (blockName != NULL) {
1403     blocks.push_back(strdup(blockName));
1404     blockName = strtok(NULL, " ");
1405   }
1406 
1407   if (blocks.size() == 0) {
1408     ndbout << "No block specified." << endl;
1409     return false;
1410   }
1411   if (blocks.size() > 1 && all) {
1412     // More than "ALL" specified
1413     ndbout << "Nothing expected after ALL." << endl;
1414     return false;
1415   }
1416 
1417   return true;
1418 }
1419 
1420 
1421 
1422 /*****************************************************************************
1423  * HELP
1424  *****************************************************************************/
1425 int
executeHelp(char * parameters)1426 CommandInterpreter::executeHelp(char* parameters)
1427 {
1428   if (emptyString(parameters)) {
1429     ndbout << helpText;
1430 
1431     ndbout << endl
1432 	   << "<severity> = "
1433 	   << "ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG"
1434 	   << endl;
1435 
1436     ndbout << "<category> = ";
1437     for(int i = CFG_MIN_LOGLEVEL; i <= CFG_MAX_LOGLEVEL; i++){
1438       const char *str= ndb_mgm_get_event_category_string((ndb_mgm_event_category)i);
1439       if (str) {
1440 	if (i != CFG_MIN_LOGLEVEL)
1441 	  ndbout << " | ";
1442 	ndbout << str;
1443       }
1444     }
1445     ndbout << endl;
1446 
1447     ndbout << "<level>    = " << "0 - 15" << endl;
1448     ndbout << "<id>       = " << "ALL | Any database node id" << endl;
1449     ndbout << endl;
1450     ndbout << "For detailed help on COMMAND, use HELP COMMAND." << endl;
1451   } else {
1452     int i = 0;
1453     for (i = 0; help_items[i].cmd != NULL; i++)
1454     {
1455       if (strcasecmp(parameters, help_items[i].cmd) == 0)
1456       {
1457         ndbout << help_items[i].help;
1458         break;
1459       }
1460     }
1461     if (help_items[i].cmd == NULL){
1462       ndbout << "No help for " << parameters << " available" << endl;
1463       return -1;
1464     }
1465   }
1466   return 0;
1467 }
1468 
1469 
1470 /*****************************************************************************
1471  * SHUTDOWN
1472  *****************************************************************************/
1473 
1474 int
executeShutdown(char * parameters)1475 CommandInterpreter::executeShutdown(char* parameters)
1476 {
1477   ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1478   if(state == NULL) {
1479     ndbout_c("Could not get status");
1480     printError();
1481     return 1;
1482   }
1483   NdbAutoPtr<char> ap1((char*)state);
1484 
1485   int result = 0;
1486   int need_disconnect;
1487   result = ndb_mgm_stop3(m_mgmsrv, -1, 0, 0, &need_disconnect);
1488   if (result < 0) {
1489     ndbout << "Shutdown of NDB Cluster node(s) failed." << endl;
1490     printError();
1491     return result;
1492   }
1493 
1494   ndbout << result << " NDB Cluster node(s) have shutdown." << endl;
1495 
1496   if(need_disconnect) {
1497     ndbout << "Disconnecting to allow management server to shutdown."
1498            << endl;
1499     disconnect();
1500   }
1501   return 0;
1502 }
1503 
1504 /*****************************************************************************
1505  * SHOW
1506  *****************************************************************************/
1507 
1508 
1509 static
status_string(ndb_mgm_node_status status)1510 const char *status_string(ndb_mgm_node_status status)
1511 {
1512   switch(status){
1513   case NDB_MGM_NODE_STATUS_NO_CONTACT:
1514     return "not connected";
1515   case NDB_MGM_NODE_STATUS_NOT_STARTED:
1516     return "not started";
1517   case NDB_MGM_NODE_STATUS_STARTING:
1518     return "starting";
1519   case NDB_MGM_NODE_STATUS_STARTED:
1520     return "started";
1521   case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
1522     return "shutting down";
1523   case NDB_MGM_NODE_STATUS_RESTARTING:
1524     return "restarting";
1525   case NDB_MGM_NODE_STATUS_SINGLEUSER:
1526     return "single user mode";
1527   default:
1528     return "unknown state";
1529   }
1530 }
1531 
1532 static void
print_nodes(ndb_mgm_cluster_state * state,ndb_mgm_configuration_iterator * it,const char * proc_name,int no_proc,ndb_mgm_node_type type,int master_id)1533 print_nodes(ndb_mgm_cluster_state *state, ndb_mgm_configuration_iterator *it,
1534 	    const char *proc_name, int no_proc, ndb_mgm_node_type type,
1535 	    int master_id)
1536 {
1537   int i;
1538   ndbout << "[" << proc_name
1539 	 << "(" << ndb_mgm_get_node_type_string(type) << ")]\t"
1540 	 << no_proc << " node(s)" << endl;
1541   for(i=0; i < state->no_of_nodes; i++) {
1542     struct ndb_mgm_node_state *node_state= &(state->node_states[i]);
1543     if(node_state->node_type == type) {
1544       int node_id= node_state->node_id;
1545       ndbout << "id=" << node_id;
1546       if(node_state->version != 0) {
1547 	const char *hostname= node_state->connect_address;
1548 	if (hostname == 0
1549 	    || strlen(hostname) == 0
1550 	    || strcasecmp(hostname,"0.0.0.0") == 0)
1551 	  ndbout << " ";
1552 	else
1553 	  ndbout << "\t@" << hostname;
1554 	ndbout << "  (Version: "
1555 	       << getMajor(node_state->version) << "."
1556 	       << getMinor(node_state->version) << "."
1557 	       << getBuild(node_state->version);
1558 	if (type == NDB_MGM_NODE_TYPE_NDB) {
1559 	  if (node_state->node_status != NDB_MGM_NODE_STATUS_STARTED) {
1560 	    ndbout << ", " << status_string(node_state->node_status);
1561 	  }
1562 	  if (node_state->node_group >= 0) {
1563 	    ndbout << ", Nodegroup: " << node_state->node_group;
1564 	    if (master_id && node_state->dynamic_id == master_id)
1565 	      ndbout << ", Master";
1566 	  }
1567 	}
1568 	ndbout << ")" << endl;
1569       } else {
1570 	ndb_mgm_first(it);
1571 	if(ndb_mgm_find(it, CFG_NODE_ID, node_id) == 0){
1572 	  const char *config_hostname= 0;
1573 	  ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &config_hostname);
1574 	  if (config_hostname == 0 || config_hostname[0] == 0)
1575 	    config_hostname= "any host";
1576 	  ndbout_c(" (not connected, accepting connect from %s)",
1577 		   config_hostname);
1578 	}
1579 	else
1580 	{
1581 	  ndbout_c("Unable to find node with id: %d", node_id);
1582 	}
1583       }
1584     }
1585   }
1586   ndbout << endl;
1587 }
1588 
1589 int
executePurge(char * parameters)1590 CommandInterpreter::executePurge(char* parameters)
1591 {
1592   int command_ok= 0;
1593   do {
1594     if (emptyString(parameters))
1595       break;
1596     char* firstToken = strtok(parameters, " ");
1597     char* nextToken = strtok(NULL, " \0");
1598     if (strcasecmp(firstToken,"STALE") == 0 &&
1599 	nextToken &&
1600 	strcasecmp(nextToken, "SESSIONS") == 0) {
1601       command_ok= 1;
1602       break;
1603     }
1604   } while(0);
1605 
1606   if (!command_ok) {
1607     ndbout_c("Unexpected command, expected: PURGE STALE SESSIONS");
1608     return -1;
1609   }
1610 
1611   char *str;
1612 
1613   if (ndb_mgm_purge_stale_sessions(m_mgmsrv, &str)) {
1614     ndbout_c("Command failed");
1615     return -1;
1616   }
1617   if (str) {
1618     ndbout_c("Purged sessions with node id's: %s", str);
1619     free(str);
1620   }
1621   else
1622   {
1623     ndbout_c("No sessions purged");
1624   }
1625   return 0;
1626 }
1627 
1628 int
executeShow(char * parameters)1629 CommandInterpreter::executeShow(char* parameters)
1630 {
1631   int i;
1632   if (emptyString(parameters)) {
1633     ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1634     if(state == NULL) {
1635       ndbout_c("Could not get status");
1636       printError();
1637       return -1;
1638     }
1639     NdbAutoPtr<char> ap1((char*)state);
1640 
1641     ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_mgmsrv,0);
1642     if(conf == 0){
1643       ndbout_c("Could not get configuration");
1644       printError();
1645       return -1;
1646     }
1647 
1648     ndb_mgm_configuration_iterator * it;
1649     it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE);
1650 
1651     if(it == 0){
1652       ndbout_c("Unable to create config iterator");
1653       ndb_mgm_destroy_configuration(conf);
1654       return -1;
1655     }
1656     NdbAutoPtr<ndb_mgm_configuration_iterator> ptr(it);
1657 
1658     int
1659       master_id= 0,
1660       ndb_nodes= 0,
1661       api_nodes= 0,
1662       mgm_nodes= 0;
1663 
1664     for(i=0; i < state->no_of_nodes; i++) {
1665       if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB &&
1666 	 state->node_states[i].version != 0){
1667 	master_id= state->node_states[i].dynamic_id;
1668 	break;
1669       }
1670     }
1671 
1672     for(i=0; i < state->no_of_nodes; i++) {
1673       switch(state->node_states[i].node_type) {
1674       case NDB_MGM_NODE_TYPE_API:
1675 	api_nodes++;
1676 	break;
1677       case NDB_MGM_NODE_TYPE_NDB:
1678 	if (state->node_states[i].dynamic_id &&
1679 	    state->node_states[i].dynamic_id < master_id)
1680 	  master_id= state->node_states[i].dynamic_id;
1681 	ndb_nodes++;
1682 	break;
1683       case NDB_MGM_NODE_TYPE_MGM:
1684 	mgm_nodes++;
1685 	break;
1686       case NDB_MGM_NODE_TYPE_UNKNOWN:
1687         ndbout << "Error: Unknown Node Type" << endl;
1688         return -1;
1689       case NDB_MGM_NODE_TYPE_MAX:
1690         break;                                  /* purify: deadcode */
1691       }
1692     }
1693 
1694     ndbout << "Cluster Configuration" << endl
1695 	   << "---------------------" << endl;
1696     print_nodes(state, it, "ndbd",     ndb_nodes, NDB_MGM_NODE_TYPE_NDB, master_id);
1697     print_nodes(state, it, "ndb_mgmd", mgm_nodes, NDB_MGM_NODE_TYPE_MGM, 0);
1698     print_nodes(state, it, "mysqld",   api_nodes, NDB_MGM_NODE_TYPE_API, 0);
1699     //    ndbout << helpTextShow;
1700     ndb_mgm_destroy_configuration(conf);
1701     return 0;
1702   } else if (strcasecmp(parameters, "PROPERTIES") == 0 ||
1703 	     strcasecmp(parameters, "PROP") == 0) {
1704     ndbout << "SHOW PROPERTIES is not yet implemented." << endl;
1705     //  ndbout << "_mgmtSrvr.getConfig()->print();" << endl; /* XXX */
1706   } else if (strcasecmp(parameters, "CONFIGURATION") == 0 ||
1707 	     strcasecmp(parameters, "CONFIG") == 0){
1708     ndbout << "SHOW CONFIGURATION is not yet implemented." << endl;
1709     //nbout << "_mgmtSrvr.getConfig()->printConfigFile();" << endl; /* XXX */
1710   } else if (strcasecmp(parameters, "PARAMETERS") == 0 ||
1711 	     strcasecmp(parameters, "PARAMS") == 0 ||
1712 	     strcasecmp(parameters, "PARAM") == 0) {
1713     ndbout << "SHOW PARAMETERS is not yet implemented." << endl;
1714     //    ndbout << "_mgmtSrvr.getConfig()->getConfigInfo()->print();"
1715     //           << endl; /* XXX */
1716   } else {
1717     ndbout << "Invalid argument." << endl;
1718     return -1;
1719   }
1720   return 0;
1721 }
1722 
1723 int
executeConnect(char * parameters,bool interactive)1724 CommandInterpreter::executeConnect(char* parameters, bool interactive)
1725 {
1726   BaseString *basestring = NULL;
1727 
1728   disconnect();
1729   if (!emptyString(parameters)) {
1730     basestring= new BaseString(parameters);
1731     m_constr= basestring->trim().c_str();
1732   }
1733   if ( connect(interactive) == false ){
1734     return -1;
1735   }
1736   if (basestring != NULL)
1737     delete basestring;
1738 
1739   return 0;
1740 }
1741 
1742 //*****************************************************************************
1743 //*****************************************************************************
1744 void
executeClusterLog(char * parameters)1745 CommandInterpreter::executeClusterLog(char* parameters)
1746 {
1747   DBUG_ENTER("CommandInterpreter::executeClusterLog");
1748   int i;
1749   if (emptyString(parameters))
1750   {
1751     ndbout << "Missing argument." << endl;
1752     m_error = -1;
1753     DBUG_VOID_RETURN;
1754   }
1755 
1756   enum ndb_mgm_event_severity severity = NDB_MGM_EVENT_SEVERITY_ALL;
1757 
1758   char * tmpString = my_strdup(parameters,MYF(MY_WME));
1759   My_auto_ptr<char> ap1(tmpString);
1760   char * tmpPtr = 0;
1761   char * item = strtok_r(tmpString, " ", &tmpPtr);
1762   int enable;
1763 
1764   ndb_mgm_severity enabled[NDB_MGM_EVENT_SEVERITY_ALL] =
1765     {{NDB_MGM_EVENT_SEVERITY_ON,0},
1766      {NDB_MGM_EVENT_SEVERITY_DEBUG,0},
1767      {NDB_MGM_EVENT_SEVERITY_INFO,0},
1768      {NDB_MGM_EVENT_SEVERITY_WARNING,0},
1769      {NDB_MGM_EVENT_SEVERITY_ERROR,0},
1770      {NDB_MGM_EVENT_SEVERITY_CRITICAL,0},
1771      {NDB_MGM_EVENT_SEVERITY_ALERT,0}};
1772   ndb_mgm_get_clusterlog_severity_filter(m_mgmsrv, &enabled[0], NDB_MGM_EVENT_SEVERITY_ALL);
1773   if(enabled == NULL) {
1774     ndbout << "Couldn't get status" << endl;
1775     printError();
1776     m_error = -1;
1777     DBUG_VOID_RETURN;
1778   }
1779 
1780   /********************
1781    * CLUSTERLOG INFO
1782    ********************/
1783   if (strcasecmp(item, "INFO") == 0) {
1784     DBUG_PRINT("info",("INFO"));
1785     if(enabled[0].value == 0)
1786     {
1787       ndbout << "Cluster logging is disabled." << endl;
1788       m_error = 0;
1789       DBUG_VOID_RETURN;
1790     }
1791 #if 0
1792     for(i = 0; i<DB_MGM_EVENT_SEVERITY_ALL;i++)
1793       printf("enabled[%d] = %d\n", i, enabled[i].value);
1794 #endif
1795     ndbout << "Severities enabled: ";
1796     for(i = 1; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
1797       const char *str= ndb_mgm_get_event_severity_string(enabled[i].category);
1798       if (str == 0)
1799       {
1800 	DBUG_ASSERT(false);
1801 	continue;
1802       }
1803       if(enabled[i].value)
1804 	ndbout << BaseString(str).ndb_toupper() << " ";
1805     }
1806     ndbout << endl;
1807     m_error = 0;
1808     DBUG_VOID_RETURN;
1809 
1810   }
1811   else if (strcasecmp(item, "FILTER") == 0 ||
1812 	   strcasecmp(item, "TOGGLE") == 0)
1813   {
1814     DBUG_PRINT("info",("TOGGLE"));
1815     enable= -1;
1816   }
1817   else if (strcasecmp(item, "OFF") == 0)
1818   {
1819     DBUG_PRINT("info",("OFF"));
1820     enable= 0;
1821   } else if (strcasecmp(item, "ON") == 0) {
1822     DBUG_PRINT("info",("ON"));
1823     enable= 1;
1824   } else {
1825     ndbout << "Invalid argument." << endl;
1826     m_error = -1;
1827     DBUG_VOID_RETURN;
1828   }
1829 
1830   int res_enable;
1831   item = strtok_r(NULL, " ", &tmpPtr);
1832   if (item == NULL) {
1833     res_enable=
1834       ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv,
1835 					     NDB_MGM_EVENT_SEVERITY_ON,
1836 					     enable, NULL);
1837     if (res_enable < 0)
1838     {
1839       ndbout << "Couldn't set filter" << endl;
1840       printError();
1841       m_error = -1;
1842       DBUG_VOID_RETURN;
1843     }
1844     ndbout << "Cluster logging is " << (res_enable ? "enabled.":"disabled") << endl;
1845     m_error = 0;
1846     DBUG_VOID_RETURN;
1847   }
1848 
1849   do {
1850     severity= NDB_MGM_ILLEGAL_EVENT_SEVERITY;
1851     if (strcasecmp(item, "ALL") == 0) {
1852       severity = NDB_MGM_EVENT_SEVERITY_ALL;
1853     } else if (strcasecmp(item, "ALERT") == 0) {
1854       severity = NDB_MGM_EVENT_SEVERITY_ALERT;
1855     } else if (strcasecmp(item, "CRITICAL") == 0) {
1856       severity = NDB_MGM_EVENT_SEVERITY_CRITICAL;
1857     } else if (strcasecmp(item, "ERROR") == 0) {
1858       severity = NDB_MGM_EVENT_SEVERITY_ERROR;
1859     } else if (strcasecmp(item, "WARNING") == 0) {
1860       severity = NDB_MGM_EVENT_SEVERITY_WARNING;
1861     } else if (strcasecmp(item, "INFO") == 0) {
1862       severity = NDB_MGM_EVENT_SEVERITY_INFO;
1863     } else if (strcasecmp(item, "DEBUG") == 0) {
1864       severity = NDB_MGM_EVENT_SEVERITY_DEBUG;
1865     } else if (strcasecmp(item, "OFF") == 0 ||
1866 	       strcasecmp(item, "ON") == 0) {
1867       if (enable < 0) // only makes sense with toggle
1868 	severity = NDB_MGM_EVENT_SEVERITY_ON;
1869     }
1870     if (severity == NDB_MGM_ILLEGAL_EVENT_SEVERITY) {
1871       ndbout << "Invalid severity level: " << item << endl;
1872       m_error = -1;
1873       DBUG_VOID_RETURN;
1874     }
1875 
1876     res_enable= ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv, severity,
1877 						       enable, NULL);
1878     if (res_enable < 0)
1879     {
1880       ndbout << "Couldn't set filter" << endl;
1881       printError();
1882       m_error = -1;
1883       DBUG_VOID_RETURN;
1884     }
1885     ndbout << BaseString(item).ndb_toupper().c_str() << " " << (res_enable ? "enabled":"disabled") << endl;
1886 
1887     item = strtok_r(NULL, " ", &tmpPtr);
1888   } while(item != NULL);
1889 
1890   m_error = 0;
1891   DBUG_VOID_RETURN;
1892 }
1893 
1894 //*****************************************************************************
1895 //*****************************************************************************
1896 
1897 int
executeStop(int processId,const char * parameters,bool all)1898 CommandInterpreter::executeStop(int processId, const char *parameters,
1899                                 bool all)
1900 {
1901   int retval = 0;
1902 
1903   Vector<BaseString> command_list;
1904   if (parameters)
1905   {
1906     BaseString tmp(parameters);
1907     tmp.split(command_list);
1908     for (unsigned i= 0; i < command_list.size();)
1909       command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
1910   }
1911   if (all)
1912     retval = executeStop(command_list, 0, 0, 0);
1913   else
1914     retval = executeStop(command_list, 0, &processId, 1);
1915 
1916   return retval;
1917 }
1918 
1919 int
executeStop(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)1920 CommandInterpreter::executeStop(Vector<BaseString> &command_list,
1921                                 unsigned command_pos,
1922                                 int *node_ids, int no_of_nodes)
1923 {
1924   int need_disconnect;
1925   int abort= 0;
1926   int retval = 0;
1927 
1928   for (; command_pos < command_list.size(); command_pos++)
1929   {
1930     const char *item= command_list[command_pos].c_str();
1931     if (strcasecmp(item, "-A") == 0)
1932     {
1933       abort= 1;
1934       continue;
1935     }
1936     ndbout_c("Invalid option: %s. Expecting -A after STOP",
1937              item);
1938     return -1;
1939   }
1940 
1941   int result= ndb_mgm_stop3(m_mgmsrv, no_of_nodes, node_ids, abort,
1942                             &need_disconnect);
1943   if (result < 0)
1944   {
1945     ndbout_c("Shutdown failed.");
1946     printError();
1947     retval = -1;
1948   }
1949   else
1950   {
1951     if (node_ids == 0)
1952       ndbout_c("NDB Cluster has shutdown.");
1953     else
1954     {
1955       ndbout << "Node";
1956       for (int i= 0; i < no_of_nodes; i++)
1957           ndbout << " " << node_ids[i];
1958       ndbout_c(" has shutdown.");
1959     }
1960   }
1961 
1962   if(need_disconnect)
1963   {
1964     ndbout << "Disconnecting to allow Management Server to shutdown" << endl;
1965     disconnect();
1966   }
1967 
1968   return retval;
1969 }
1970 
1971 int
executeEnterSingleUser(char * parameters)1972 CommandInterpreter::executeEnterSingleUser(char* parameters)
1973 {
1974   strtok(parameters, " ");
1975   struct ndb_mgm_reply reply;
1976   char* id = strtok(NULL, " ");
1977   id = strtok(NULL, " ");
1978   id = strtok(NULL, "\0");
1979   int nodeId = -1;
1980   if(id == 0 || sscanf(id, "%d", &nodeId) != 1){
1981     ndbout_c("Invalid arguments: expected <NodeId>");
1982     ndbout_c("Use SHOW to see what API nodes are configured");
1983     return -1;
1984   }
1985   int result = ndb_mgm_enter_single_user(m_mgmsrv, nodeId, &reply);
1986 
1987   if (result != 0) {
1988     ndbout_c("Entering single user mode for node %d failed", nodeId);
1989     printError();
1990     return -1;
1991   } else {
1992     ndbout_c("Single user mode entered");
1993     ndbout_c("Access is granted for API node %d only.", nodeId);
1994   }
1995   return 0;
1996 }
1997 
1998 int
executeExitSingleUser(char * parameters)1999 CommandInterpreter::executeExitSingleUser(char* parameters)
2000 {
2001   int result = ndb_mgm_exit_single_user(m_mgmsrv, 0);
2002   if (result != 0) {
2003     ndbout_c("Exiting single user mode failed.");
2004     printError();
2005     return -1;
2006   } else {
2007     ndbout_c("Exiting single user mode in progress.");
2008     ndbout_c("Use ALL STATUS or SHOW to see when single user mode has been exited.");
2009     return 0;
2010   }
2011 }
2012 
2013 int
executeStart(int processId,const char * parameters,bool all)2014 CommandInterpreter::executeStart(int processId, const char* parameters,
2015 				 bool all)
2016 {
2017   int result;
2018   int retval = 0;
2019   if(all) {
2020     result = ndb_mgm_start(m_mgmsrv, 0, 0);
2021   } else {
2022     result = ndb_mgm_start(m_mgmsrv, 1, &processId);
2023   }
2024 
2025   if (result <= 0) {
2026     ndbout << "Start failed." << endl;
2027     printError();
2028     retval = -1;
2029   } else
2030     {
2031       if(all)
2032 	ndbout_c("NDB Cluster is being started.");
2033       else
2034 	ndbout_c("Database node %d is being started.", processId);
2035     }
2036   return retval;
2037 }
2038 
2039 int
executeRestart(int processId,const char * parameters,bool all)2040 CommandInterpreter::executeRestart(int processId, const char* parameters,
2041 				   bool all)
2042 {
2043   Vector<BaseString> command_list;
2044   int retval = 0;
2045 
2046   if (parameters)
2047   {
2048     BaseString tmp(parameters);
2049     tmp.split(command_list);
2050     for (unsigned i= 0; i < command_list.size();)
2051       command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
2052   }
2053   if (all)
2054     retval = executeRestart(command_list, 0, 0, 0);
2055   else
2056     retval = executeRestart(command_list, 0, &processId, 1);
2057 
2058   return retval;
2059 }
2060 
2061 int
executeRestart(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)2062 CommandInterpreter::executeRestart(Vector<BaseString> &command_list,
2063                                    unsigned command_pos,
2064                                    int *node_ids, int no_of_nodes)
2065 {
2066   int result;
2067   int retval = 0;
2068   int nostart= 0;
2069   int initialstart= 0;
2070   int abort= 0;
2071   int need_disconnect= 0;
2072 
2073   for (; command_pos < command_list.size(); command_pos++)
2074   {
2075     const char *item= command_list[command_pos].c_str();
2076     if (strcasecmp(item, "-N") == 0)
2077     {
2078       nostart= 1;
2079       continue;
2080     }
2081     if (strcasecmp(item, "-I") == 0)
2082     {
2083       initialstart= 1;
2084       continue;
2085     }
2086     if (strcasecmp(item, "-A") == 0)
2087     {
2088       abort= 1;
2089       continue;
2090     }
2091     ndbout_c("Invalid option: %s. Expecting -A,-N or -I after RESTART",
2092              item);
2093     return -1;
2094   }
2095 
2096   if (nostart)
2097     ndbout_c("Shutting down nodes with \"-n, no start\" option, to subsequently start the nodes.");
2098 
2099   result= ndb_mgm_restart3(m_mgmsrv, no_of_nodes, node_ids,
2100                            initialstart, nostart, abort, &need_disconnect);
2101 
2102   if (result <= 0) {
2103     ndbout_c("Restart failed.");
2104     printError();
2105     retval = -1;
2106   }
2107   else
2108   {
2109     if (node_ids == 0)
2110       ndbout_c("NDB Cluster is being restarted.");
2111     else
2112     {
2113       ndbout << "Node";
2114       for (int i= 0; i < no_of_nodes; i++)
2115         ndbout << " " << node_ids[i];
2116       ndbout_c(" is being restarted");
2117     }
2118     if(need_disconnect)
2119       disconnect();
2120   }
2121   return retval;
2122 }
2123 
2124 int
executeDumpState(int processId,const char * parameters,bool all)2125 CommandInterpreter::executeDumpState(int processId, const char* parameters,
2126 				     bool all)
2127 {
2128   if(emptyString(parameters)){
2129     ndbout << "Expected argument" << endl;
2130     return -1;
2131   }
2132 
2133   Uint32 no = 0;
2134   int pars[25];
2135 
2136   char * tmpString = my_strdup(parameters,MYF(MY_WME));
2137   My_auto_ptr<char> ap1(tmpString);
2138   char * tmpPtr = 0;
2139   char * item = strtok_r(tmpString, " ", &tmpPtr);
2140   while(item != NULL){
2141     if (0x0 <= strtoll(item, NULL, 0) && strtoll(item, NULL, 0) <= 0xffffffff){
2142       pars[no] = strtoll(item, NULL, 0);
2143     } else {
2144       ndbout << "Illegal value in argument to signal." << endl
2145 	     << "(Value must be between 0 and 0xffffffff.)"
2146 	     << endl;
2147       return -1;
2148     }
2149     no++;
2150     item = strtok_r(NULL, " ", &tmpPtr);
2151   }
2152   ndbout << "Sending dump signal with data:" << endl;
2153   for (Uint32 i=0; i<no; i++) {
2154     ndbout.setHexFormat(1) << pars[i] << " ";
2155     if (!(i+1 & 0x3)) ndbout << endl;
2156   }
2157 
2158   struct ndb_mgm_reply reply;
2159   return ndb_mgm_dump_state(m_mgmsrv, processId, pars, no, &reply);
2160 }
2161 
2162 int
executeStatus(int processId,const char * parameters,bool all)2163 CommandInterpreter::executeStatus(int processId,
2164 				  const char* parameters, bool all)
2165 {
2166   if (! emptyString(parameters)) {
2167     ndbout_c("No parameters expected to this command.");
2168     return -1;
2169   }
2170 
2171   ndb_mgm_node_status status;
2172   Uint32 startPhase, version;
2173 
2174   struct ndb_mgm_cluster_state *cl;
2175   cl = ndb_mgm_get_status(m_mgmsrv);
2176   if(cl == NULL) {
2177     ndbout_c("Cannot get status of node %d.", processId);
2178     printError();
2179     return -1;
2180   }
2181   NdbAutoPtr<char> ap1((char*)cl);
2182 
2183   int i = 0;
2184   while((i < cl->no_of_nodes) && cl->node_states[i].node_id != processId)
2185     i++;
2186   if(cl->node_states[i].node_id != processId) {
2187     ndbout << processId << ": Node not found" << endl;
2188     return -1;
2189   }
2190   if (cl->node_states[i].node_type != NDB_MGM_NODE_TYPE_NDB){
2191     if (cl->node_states[i].version != 0){
2192       version = cl->node_states[i].version;
2193       ndbout << "Node "<< cl->node_states[i].node_id <<": connected" ;
2194       ndbout_c(" (Version %d.%d.%d)",
2195              getMajor(version) ,
2196              getMinor(version),
2197              getBuild(version));
2198 
2199     }else
2200      ndbout << "Node "<< cl->node_states[i].node_id <<": not connected" << endl;
2201     return 0;
2202   }
2203   status = cl->node_states[i].node_status;
2204   startPhase = cl->node_states[i].start_phase;
2205   version = cl->node_states[i].version;
2206 
2207   ndbout << "Node " << processId << ": " << status_string(status);
2208   switch(status){
2209   case NDB_MGM_NODE_STATUS_STARTING:
2210     ndbout << " (Phase " << startPhase << ")";
2211     break;
2212   case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
2213     ndbout << " (Phase " << startPhase << ")";
2214     break;
2215   default:
2216     break;
2217   }
2218   if(status != NDB_MGM_NODE_STATUS_NO_CONTACT)
2219     ndbout_c(" (Version %d.%d.%d)",
2220 	     getMajor(version) ,
2221 	     getMinor(version),
2222 	     getBuild(version));
2223   else
2224     ndbout << endl;
2225 
2226   return 0;
2227 }
2228 
2229 
2230 //*****************************************************************************
2231 //*****************************************************************************
2232 
2233 int
executeLogLevel(int processId,const char * parameters,bool all)2234 CommandInterpreter::executeLogLevel(int processId, const char* parameters,
2235 				    bool all)
2236 {
2237   (void) all;
2238   if (emptyString(parameters)) {
2239     ndbout << "Expected argument" << endl;
2240     return -1;
2241   }
2242   BaseString tmp(parameters);
2243   Vector<BaseString> spec;
2244   tmp.split(spec, "=");
2245   if(spec.size() != 2){
2246     ndbout << "Invalid loglevel specification: " << parameters << endl;
2247     return -1;
2248   }
2249 
2250   spec[0].trim().ndb_toupper();
2251   int category = ndb_mgm_match_event_category(spec[0].c_str());
2252   if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2253     category = atoi(spec[0].c_str());
2254     if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
2255        category > NDB_MGM_MAX_EVENT_CATEGORY){
2256       ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2257       return -1;
2258     }
2259   }
2260 
2261   int level = atoi(spec[1].c_str());
2262   if(level < 0 || level > 15){
2263     ndbout << "Invalid level: " << spec[1].c_str() << endl;
2264     return -1;
2265   }
2266 
2267   ndbout << "Executing LOGLEVEL on node " << processId << flush;
2268 
2269   struct ndb_mgm_reply reply;
2270   int result;
2271   result = ndb_mgm_set_loglevel_node(m_mgmsrv,
2272 				     processId,
2273 				     (ndb_mgm_event_category)category,
2274 				     level,
2275 				     &reply);
2276 
2277   if (result < 0) {
2278     ndbout_c(" failed.");
2279     printError();
2280     return -1;
2281   } else {
2282     ndbout_c(" OK!");
2283   }
2284   return 0;
2285 }
2286 
2287 //*****************************************************************************
2288 //*****************************************************************************
executeError(int processId,const char * parameters,bool)2289 int CommandInterpreter::executeError(int processId,
2290 				      const char* parameters, bool /* all */)
2291 {
2292   int retval = 0;
2293   if (emptyString(parameters)) {
2294     ndbout << "Missing error number." << endl;
2295     return -1;
2296   }
2297 
2298   // Copy parameters since strtok will modify it
2299   char* newpar = my_strdup(parameters,MYF(MY_WME));
2300   My_auto_ptr<char> ap1(newpar);
2301   char* firstParameter = strtok(newpar, " ");
2302 
2303   int errorNo;
2304   if (! convert(firstParameter, errorNo)) {
2305     ndbout << "Expected an integer." << endl;
2306     return -1;
2307   }
2308 
2309   char* allAfterFirstParameter = strtok(NULL, "\0");
2310   if (! emptyString(allAfterFirstParameter)) {
2311     ndbout << "Nothing expected after error number." << endl;
2312     return -1;
2313   }
2314 
2315   retval = ndb_mgm_insert_error(m_mgmsrv, processId, errorNo, NULL);
2316   return retval;
2317 }
2318 
2319 //*****************************************************************************
2320 //*****************************************************************************
2321 
2322 int
executeLog(int processId,const char * parameters,bool all)2323 CommandInterpreter::executeLog(int processId,
2324 			       const char* parameters, bool all)
2325 {
2326   struct ndb_mgm_reply reply;
2327   Vector<const char *> blocks;
2328   if (! parseBlockSpecification(parameters, blocks)) {
2329     return -1;
2330   }
2331   int len=1;
2332   Uint32 i;
2333   for(i=0; i<blocks.size(); i++) {
2334     len += strlen(blocks[i]) + 1;
2335   }
2336   char * blockNames = (char*)my_malloc(len,MYF(MY_WME));
2337   My_auto_ptr<char> ap1(blockNames);
2338 
2339   blockNames[0] = 0;
2340   for(i=0; i<blocks.size(); i++) {
2341     strcat(blockNames, blocks[i]);
2342     strcat(blockNames, "|");
2343   }
2344 
2345   int result = ndb_mgm_log_signals(m_mgmsrv,
2346 				   processId,
2347 				   NDB_MGM_SIGNAL_LOG_MODE_INOUT,
2348 				   blockNames,
2349 				   &reply);
2350   if (result != 0) {
2351     ndbout_c("Execute LOG on node %d failed.", processId);
2352     printError();
2353     return -1;
2354   }
2355   return 0;
2356 }
2357 
2358 //*****************************************************************************
2359 //*****************************************************************************
2360 int
executeLogIn(int,const char * parameters,bool)2361 CommandInterpreter::executeLogIn(int /* processId */,
2362 				 const char* parameters, bool /* all */)
2363 {
2364   ndbout << "Command LOGIN not implemented." << endl;
2365   return 0;
2366 }
2367 
2368 //*****************************************************************************
2369 //*****************************************************************************
2370 int
executeLogOut(int,const char * parameters,bool)2371 CommandInterpreter::executeLogOut(int /*processId*/,
2372 				  const char* parameters, bool /*all*/)
2373 {
2374   ndbout << "Command LOGOUT not implemented." << endl;
2375   return 0;
2376 }
2377 
2378 //*****************************************************************************
2379 //*****************************************************************************
2380 int
executeLogOff(int,const char * parameters,bool)2381 CommandInterpreter::executeLogOff(int /*processId*/,
2382 				  const char* parameters, bool /*all*/)
2383 {
2384   ndbout << "Command LOGOFF not implemented." << endl;
2385   return 0;
2386 }
2387 
2388 //*****************************************************************************
2389 //*****************************************************************************
2390 int
executeTestOn(int processId,const char * parameters,bool)2391 CommandInterpreter::executeTestOn(int processId,
2392 				  const char* parameters, bool /*all*/)
2393 {
2394   if (! emptyString(parameters)) {
2395     ndbout << "No parameters expected to this command." << endl;
2396     return -1;
2397   }
2398   struct ndb_mgm_reply reply;
2399   int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply);
2400   if (result != 0) {
2401     ndbout_c("Execute TESTON failed.");
2402     printError();
2403     return -1;
2404   }
2405   return 0;
2406 }
2407 
2408 //*****************************************************************************
2409 //*****************************************************************************
2410 int
executeTestOff(int processId,const char * parameters,bool)2411 CommandInterpreter::executeTestOff(int processId,
2412 				   const char* parameters, bool /*all*/)
2413 {
2414   if (! emptyString(parameters)) {
2415     ndbout << "No parameters expected to this command." << endl;
2416     return -1;
2417   }
2418   struct ndb_mgm_reply reply;
2419   int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply);
2420   if (result != 0) {
2421     ndbout_c("Execute TESTOFF failed.");
2422     printError();
2423     return -1;
2424   }
2425   return 0;
2426 }
2427 
2428 
2429 //*****************************************************************************
2430 //*****************************************************************************
2431 int
executeSet(int,const char * parameters,bool)2432 CommandInterpreter::executeSet(int /*processId*/,
2433 			       const char* parameters, bool /*all*/)
2434 {
2435   if (emptyString(parameters)) {
2436     ndbout << "Missing parameter name." << endl;
2437     return -1;
2438   }
2439 #if 0
2440   // Copy parameters since strtok will modify it
2441   char* newpar = my_strdup(parameters,MYF(MY_WME));
2442   My_auto_ptr<char> ap1(newpar);
2443   char* configParameterName = strtok(newpar, " ");
2444 
2445   char* allAfterParameterName = strtok(NULL, "\0");
2446   if (emptyString(allAfterParameterName)) {
2447     ndbout << "Missing parameter value." << endl;
2448     return;
2449   }
2450 
2451   char* value = strtok(allAfterParameterName, " ");
2452 
2453   char* allAfterValue = strtok(NULL, "\0");
2454   if (! emptyString(allAfterValue)) {
2455     ndbout << "Nothing expected after parameter value." << endl;
2456     return;
2457   }
2458 
2459   bool configBackupFileUpdated;
2460   bool configPrimaryFileUpdated;
2461 
2462   // TODO The handling of the primary and backup config files should be
2463   // analysed further.
2464   // How it should be handled if only the backup is possible to write.
2465 
2466   int result = _mgmtSrvr.updateConfigParam(processId, configParameterName,
2467 					   value, configBackupFileUpdated,
2468 					   configPrimaryFileUpdated);
2469   if (result == 0) {
2470     if (configBackupFileUpdated && configPrimaryFileUpdated) {
2471       ndbout << "The configuration is updated." << endl;
2472     }
2473     else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
2474       ndbout << "The configuration is updated but it was only possible "
2475 	     << "to update the backup configuration file, not the primary."
2476 	     << endl;
2477     }
2478     else {
2479       assert(false);
2480     }
2481   }
2482   else {
2483     ndbout << get_error_text(result) << endl;
2484     if (configBackupFileUpdated && configPrimaryFileUpdated) {
2485       ndbout << "The configuration files are however updated and "
2486 	     << "the value will be used next time the process is restarted."
2487 	     << endl;
2488     }
2489     else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
2490       ndbout << "It was only possible to update the backup "
2491 	     << "configuration file, not the primary." << endl;
2492     }
2493     else if (!configBackupFileUpdated && !configPrimaryFileUpdated) {
2494       ndbout << "The configuration files are not updated." << endl;
2495     }
2496     else {
2497       // The primary is not tried to write if the write of backup file fails
2498       abort();
2499     }
2500   }
2501 #endif
2502   return 0;
2503 }
2504 
2505 //*****************************************************************************
2506 //*****************************************************************************
executeGetStat(int,const char * parameters,bool)2507 int CommandInterpreter::executeGetStat(int /*processId*/,
2508 					const char* parameters, bool /*all*/)
2509 {
2510   if (! emptyString(parameters)) {
2511     ndbout << "No parameters expected to this command." << endl;
2512     return -1;
2513   }
2514 
2515 #if 0
2516   MgmtSrvr::Statistics statistics;
2517   int result = _mgmtSrvr.getStatistics(processId, statistics);
2518   if (result != 0) {
2519     ndbout << get_error_text(result) << endl;
2520     return;
2521   }
2522 #endif
2523   // Print statistic...
2524   /*
2525   ndbout << "Number of GETSTAT commands: "
2526   << statistics._test1 << endl;
2527   */
2528   return 0;
2529 }
2530 
2531 //*****************************************************************************
2532 //*****************************************************************************
2533 
2534 int
executeEventReporting(int processId,const char * parameters,bool all)2535 CommandInterpreter::executeEventReporting(int processId,
2536 					  const char* parameters,
2537 					  bool all)
2538 {
2539   int retval = 0;
2540   if (emptyString(parameters)) {
2541     ndbout << "Expected argument" << endl;
2542     return -1;
2543   }
2544   BaseString tmp(parameters);
2545   Vector<BaseString> specs;
2546   tmp.split(specs, " ");
2547 
2548   for (int i=0; i < (int) specs.size(); i++)
2549   {
2550     Vector<BaseString> spec;
2551     specs[i].split(spec, "=");
2552     if(spec.size() != 2){
2553       ndbout << "Invalid loglevel specification: " << specs[i] << endl;
2554       continue;
2555     }
2556 
2557     spec[0].trim().ndb_toupper();
2558     int category = ndb_mgm_match_event_category(spec[0].c_str());
2559     if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2560       if(!convert(spec[0].c_str(), category) ||
2561 	 category < NDB_MGM_MIN_EVENT_CATEGORY ||
2562 	 category > NDB_MGM_MAX_EVENT_CATEGORY){
2563 	ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2564 	continue;
2565       }
2566     }
2567 
2568     int level;
2569     if (!convert(spec[1].c_str(),level))
2570     {
2571       ndbout << "Invalid level: " << spec[1].c_str() << endl;
2572       continue;
2573     }
2574 
2575     ndbout << "Executing CLUSTERLOG " << spec[0] << "=" << spec[1]
2576 	   << " on node " << processId << flush;
2577 
2578     struct ndb_mgm_reply reply;
2579     int result;
2580     result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv,
2581 					     processId,
2582 					     (ndb_mgm_event_category)category,
2583 					     level,
2584 					     &reply);
2585 
2586     if (result != 0) {
2587       ndbout_c(" failed.");
2588       printError();
2589       retval = -1;
2590     } else {
2591       ndbout_c(" OK!");
2592     }
2593   }
2594   return retval;
2595 }
2596 
2597 
2598 /*****************************************************************************
2599  * Backup
2600  *****************************************************************************/
2601 int
executeStartBackup(char * parameters,bool interactive)2602 CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
2603 {
2604   struct ndb_mgm_reply reply;
2605   unsigned int backupId;
2606 
2607   Vector<BaseString> args;
2608   {
2609     BaseString(parameters).split(args);
2610     for (unsigned i= 0; i < args.size(); i++)
2611       if (args[i].length() == 0)
2612 	args.erase(i--);
2613       else
2614 	args[i].ndb_toupper();
2615   }
2616   int sz= args.size();
2617 
2618   int result;
2619   int flags = 2;
2620   if (sz == 2 && args[1] == "NOWAIT")
2621   {
2622     flags = 0;
2623   }
2624   else if (sz == 1 || (sz == 3 && args[1] == "WAIT" && args[2] == "COMPLETED"))
2625   {
2626     flags = 2;
2627     ndbout_c("Waiting for completed, this may take several minutes");
2628   }
2629   else if (sz == 3 && args[1] == "WAIT" && args[2] == "STARTED")
2630   {
2631     ndbout_c("Waiting for started, this may take several minutes");
2632     flags = 1;
2633   }
2634   else
2635   {
2636     invalid_command(parameters);
2637     return -1;
2638   }
2639 
2640   NdbLogEventHandle log_handle= NULL;
2641   struct ndb_logevent log_event;
2642   if (flags == 2 && !interactive)
2643   {
2644     int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0, 0 };
2645     log_handle = ndb_mgm_create_logevent_handle(m_mgmsrv, filter);
2646     if (!log_handle)
2647     {
2648       ndbout << "Initializing start of backup failed" << endl;
2649       printError();
2650       return -1;
2651     }
2652   }
2653   result = ndb_mgm_start_backup(m_mgmsrv, flags, &backupId, &reply);
2654 
2655   if (result != 0) {
2656     ndbout << "Backup failed" << endl;
2657     printError();
2658 
2659     if (log_handle)
2660       ndb_mgm_destroy_logevent_handle(&log_handle);
2661     return result;
2662   }
2663 
2664   /**
2665    * If interactive, event listner thread is already running
2666    */
2667   if (log_handle && !interactive)
2668   {
2669     int count = 0;
2670     int retry = 0;
2671     int res;
2672     do {
2673       if ((res= ndb_logevent_get_next(log_handle, &log_event, 60000)) > 0)
2674       {
2675         int print = 0;
2676         switch (log_event.type) {
2677           case NDB_LE_BackupStarted:
2678             if (log_event.BackupStarted.backup_id == backupId)
2679               print = 1;
2680             break;
2681           case NDB_LE_BackupCompleted:
2682             if (log_event.BackupCompleted.backup_id == backupId)
2683               print = 1;
2684             break;
2685           case NDB_LE_BackupAborted:
2686             if (log_event.BackupAborted.backup_id == backupId)
2687               print = 1;
2688             break;
2689           default:
2690             break;
2691         }
2692         if (print)
2693         {
2694           Guard g(m_print_mutex);
2695           printLogEvent(&log_event);
2696           count++;
2697         }
2698       }
2699       else
2700       {
2701         retry++;
2702       }
2703     } while(res >= 0 && count < 2 && retry < 3);
2704 
2705     if (retry >= 3)
2706       ndbout << "get backup event failed for " << retry << " times" << endl;
2707 
2708     ndb_mgm_destroy_logevent_handle(&log_handle);
2709   }
2710 
2711   return 0;
2712 }
2713 
2714 int
executeAbortBackup(char * parameters)2715 CommandInterpreter::executeAbortBackup(char* parameters)
2716 {
2717   int bid = -1;
2718   struct ndb_mgm_reply reply;
2719   if (emptyString(parameters))
2720     goto executeAbortBackupError1;
2721 
2722   {
2723     strtok(parameters, " ");
2724     char* id = strtok(NULL, "\0");
2725     if(id == 0 || sscanf(id, "%d", &bid) != 1)
2726       goto executeAbortBackupError1;
2727   }
2728   {
2729     int result= ndb_mgm_abort_backup(m_mgmsrv, bid, &reply);
2730     if (result != 0) {
2731       ndbout << "Abort of backup " << bid << " failed" << endl;
2732       printError();
2733       return -1;
2734     } else {
2735       ndbout << "Abort of backup " << bid << " ordered" << endl;
2736     }
2737   }
2738   return 0;
2739  executeAbortBackupError1:
2740   ndbout << "Invalid arguments: expected <BackupId>" << endl;
2741   return -1;
2742 }
2743 
2744 template class Vector<char const*>;
2745