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