1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <ndb_opts.h>
27 
28 // copied from mysql.cc to get readline
29 extern "C" {
30 #if defined( __WIN__)
31 #include <conio.h>
32 #elif !defined(__NETWARE__)
33 #include <readline/readline.h>
34 extern "C" int add_history(const char *command); /* From readline directory */
35 extern "C" int read_history(const char *command);
36 extern "C" int write_history(const char *command);
37 #define HAVE_READLINE
38 #endif
39 }
40 
41 #include <NdbMain.h>
42 #include <BaseString.hpp>
43 #include <NdbOut.hpp>
44 #include <mgmapi.h>
45 #include <ndb_version.h>
46 
47 #include "ndb_mgmclient.hpp"
48 
49 const char *load_default_groups[]= { "mysql_cluster","ndb_mgm",0 };
50 
51 
52 static Ndb_mgmclient* com;
53 
54 static const char default_prompt[]= "ndb_mgm> ";
55 static unsigned opt_try_reconnect;
56 static const char *prompt= default_prompt;
57 static char *opt_execute_str= 0;
58 static unsigned opt_verbose = 1;
59 
60 static struct my_option my_long_options[] =
61 {
62   NDB_STD_OPTS("ndb_mgm"),
63   { "execute", 'e',
64     "execute command and exit",
65     (uchar**) &opt_execute_str, (uchar**) &opt_execute_str, 0,
66     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
67   { "try-reconnect", 't',
68     "Specify number of tries for connecting to ndb_mgmd (0 = infinite)",
69     (uchar**) &opt_try_reconnect, (uchar**) &opt_try_reconnect, 0,
70     GET_UINT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0 },
71   { "verbose", 'v',
72     "Control the amount of printout",
73     (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
74     GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
75   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
76 };
77 
short_usage_sub(void)78 static void short_usage_sub(void)
79 {
80   ndb_short_usage_sub("[hostname [port]]");
81 }
82 
usage()83 static void usage()
84 {
85   ndb_usage(short_usage_sub, load_default_groups, my_long_options);
86 }
87 
88 static bool
read_and_execute(int try_reconnect)89 read_and_execute(int try_reconnect)
90 {
91   static char *line_read = (char *)NULL;
92 
93   /* If the buffer has already been allocated, return the memory
94      to the free pool. */
95   if (line_read)
96   {
97     free (line_read);
98     line_read = (char *)NULL;
99   }
100 #ifdef HAVE_READLINE
101   /* Get a line from the user. */
102   line_read = readline (prompt);
103   /* If the line has any text in it, save it on the history. */
104   if (line_read && *line_read)
105     add_history (line_read);
106 #else
107   static char linebuffer[254];
108   fputs(prompt, stdout);
109   linebuffer[sizeof(linebuffer)-1]=0;
110   line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin);
111   if (line_read == linebuffer) {
112     char *q=linebuffer;
113     while (*q > 31) q++;
114     *q=0;
115     line_read= strdup(linebuffer);
116   }
117 #endif
118   return com->execute(line_read, try_reconnect, 1);
119 }
120 
main(int argc,char ** argv)121 int main(int argc, char** argv){
122   NDB_INIT(argv[0]);
123 
124   ndb_opt_set_usage_funcs(short_usage_sub, usage);
125   load_defaults("my",load_default_groups,&argc,&argv);
126   int ho_error;
127 #ifndef DBUG_OFF
128   opt_debug= "d:t:O,/tmp/ndb_mgm.trace";
129 #endif
130   if ((ho_error=handle_options(&argc, &argv, my_long_options,
131 			       ndb_std_get_one_option)))
132     exit(ho_error);
133 
134   BaseString connect_str(opt_ndb_connectstring);
135   if(argc == 1) {
136     connect_str.assfmt("%s", argv[0]);
137   } else if (argc >= 2) {
138     connect_str.assfmt("%s:%s", argv[0], argv[1]);
139   }
140 
141   if (!isatty(0) || opt_execute_str)
142   {
143     prompt= 0;
144   }
145 
146   com = new Ndb_mgmclient(connect_str.c_str(), opt_verbose);
147   int ret= 0;
148   BaseString histfile;
149   if (!opt_execute_str)
150   {
151 #ifdef HAVE_READLINE
152     char *histfile_env= getenv("NDB_MGM_HISTFILE");
153     if (histfile_env)
154       histfile.assign(histfile_env,strlen(histfile_env));
155     else if(getenv("HOME"))
156     {
157       histfile.assign(getenv("HOME"),strlen(getenv("HOME")));
158       histfile.append("/.ndb_mgm_history");
159     }
160     if (histfile.length())
161       read_history(histfile.c_str());
162 #endif
163 
164     ndbout << "-- NDB Cluster -- Management Client --" << endl;
165     while(read_and_execute(opt_try_reconnect))
166       ;
167 
168 #ifdef HAVE_READLINE
169     if (histfile.length())
170     {
171       BaseString histfile_tmp;
172       histfile_tmp.assign(histfile);
173       histfile_tmp.append(".TMP");
174       if(!write_history(histfile_tmp.c_str()))
175         my_rename(histfile_tmp.c_str(), histfile.c_str(), MYF(MY_WME));
176     }
177 #endif
178   }
179   else
180   {
181     com->execute(opt_execute_str, opt_try_reconnect, 0, &ret);
182   }
183   delete com;
184 
185   ndb_end(opt_ndb_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
186 
187   // Don't allow negative return code
188   if (ret < 0)
189     ret = 255;
190   return ret;
191 }
192 
193