1 /*
2 Copyright (c) 2003, 2018, 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 #include "my_alloc.h"
29
30 // copied from mysql.cc to get readline
31 extern "C" {
32 #if defined(_WIN32)
33 #include <conio.h>
34 #elif !defined(__NETWARE__)
35 #include <readline.h>
36 extern "C" int add_history(const char *command); /* From readline directory */
37 extern "C" int read_history(const char *command);
38 extern "C" int write_history(const char *command);
39 #define HAVE_READLINE
40 #endif
41 }
42
43 #include <BaseString.hpp>
44 #include <NdbOut.hpp>
45 #include <mgmapi.h>
46 #include <ndb_version.h>
47
48 #include "ndb_mgmclient.hpp"
49
50 const char *load_default_groups[]= { "mysql_cluster","ndb_mgm",0 };
51
52 static char *opt_execute_str= 0;
53 static char *opt_prompt= 0;
54 static unsigned opt_verbose = 1;
55
56 static struct my_option my_long_options[] =
57 {
58 NDB_STD_OPTS("ndb_mgm"),
59 { "execute", 'e',
60 "execute command and exit",
61 (uchar**) &opt_execute_str, (uchar**) &opt_execute_str, 0,
62 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
63 { "prompt", 'p',
64 "Set prompt to string specified",
65 (uchar**) &opt_prompt, (uchar**) &opt_prompt, 0,
66 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
67 { "verbose", 'v',
68 "Control the amount of printout",
69 (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
70 GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, \
71 {"try-reconnect", 't', \
72 "Same as --connect-retries", \
73 (uchar**) &opt_connect_retries, (uchar**) &opt_connect_retries, 0, \
74 GET_INT, REQUIRED_ARG, 12, 0, INT_MAX, 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
83 static bool
read_and_execute(Ndb_mgmclient * com,int try_reconnect)84 read_and_execute(Ndb_mgmclient* com, int try_reconnect)
85 {
86 static char *line_read = (char *)NULL;
87
88 /* If the buffer has already been allocated, return the memory
89 to the free pool. */
90 if (line_read)
91 {
92 free (line_read);
93 line_read = (char *)NULL;
94 }
95 #ifdef HAVE_READLINE
96 /* Get a line from the user. */
97 line_read = readline (com->get_current_prompt());
98 /* If the line has any text in it, save it on the history. */
99 if (line_read && *line_read)
100 add_history (line_read);
101 #else
102 static char linebuffer[254];
103 fputs(com->get_current_prompt(), stdout);
104 linebuffer[sizeof(linebuffer)-1]=0;
105 line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin);
106 if (line_read == linebuffer) {
107 char *q=linebuffer;
108 while (*q > 31) q++;
109 *q=0;
110 line_read= strdup(linebuffer);
111 }
112 #endif
113 return com->execute(line_read, try_reconnect, 1);
114 }
115
main(int argc,char ** argv)116 int main(int argc, char** argv){
117 NDB_INIT(argv[0]);
118
119 Ndb_opts opts(argc, argv, my_long_options, load_default_groups);
120 opts.set_usage_funcs(short_usage_sub);
121
122 int ho_error;
123 #ifndef DBUG_OFF
124 opt_debug= "d:t:O,/tmp/ndb_mgm.trace";
125 #endif
126 if ((ho_error=opts.handle_options()))
127 exit(ho_error);
128
129 BaseString connect_str(opt_ndb_connectstring);
130 if(argc == 1) {
131 connect_str.assfmt("%s", argv[0]);
132 } else if (argc >= 2) {
133 connect_str.assfmt("%s:%s", argv[0], argv[1]);
134 }
135
136 if (!isatty(0) || opt_execute_str)
137 {
138 opt_prompt= 0;
139 }
140
141 Ndb_mgmclient* com = new Ndb_mgmclient(connect_str.c_str(),
142 "ndb_mgm> ",
143 opt_verbose,
144 opt_connect_retry_delay);
145 if(opt_prompt)
146 {
147 /* Construct argument to be sent to execute function */
148 BaseString prompt_args("prompt ");
149 prompt_args.append(opt_prompt);
150 com->execute(prompt_args.c_str(), opt_connect_retries, 0);
151 }
152 int ret= 0;
153 BaseString histfile;
154 if (!opt_execute_str)
155 {
156 #ifdef HAVE_READLINE
157 char *histfile_env= getenv("NDB_MGM_HISTFILE");
158 if (histfile_env)
159 histfile.assign(histfile_env,strlen(histfile_env));
160 else if(getenv("HOME"))
161 {
162 histfile.assign(getenv("HOME"),strlen(getenv("HOME")));
163 histfile.append("/.ndb_mgm_history");
164 }
165 if (histfile.length())
166 read_history(histfile.c_str());
167 #endif
168
169 ndbout << "-- NDB Cluster -- Management Client --" << endl;
170 while(read_and_execute(com, opt_connect_retries))
171 ;
172
173 #ifdef HAVE_READLINE
174 if (histfile.length())
175 {
176 BaseString histfile_tmp;
177 histfile_tmp.assign(histfile);
178 histfile_tmp.append(".TMP");
179 if(!write_history(histfile_tmp.c_str()))
180 my_rename(histfile_tmp.c_str(), histfile.c_str(), MYF(MY_WME));
181 }
182 #endif
183 }
184 else
185 {
186 com->execute(opt_execute_str, opt_connect_retries, 0, &ret);
187 }
188 delete com;
189 ndb_end(opt_ndb_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
190
191 // Don't allow negative return code
192 if (ret < 0)
193 ret = 255;
194 return ret;
195 }
196
197