0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CommandInterpreter.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3 of the
9  * License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
26 
27 #include <Common/Compat.h>
28 
29 #include "CommandInterpreter.h"
30 
31 #include <ThriftBroker/Client.h>
32 
33 #include <Common/Error.h>
34 #include <Common/Logger.h>
35 #include <Common/Status.h>
37 
38 #include <boost/algorithm/string.hpp>
39 #include <boost/tokenizer.hpp>
40 
41 #include <algorithm>
42 #include <cctype>
43 #include <cerrno>
44 #include <iostream>
45 #include <string>
46 #include <vector>
47 
48 extern "C" {
49 #include <strings.h>
50 }
51 
52 using namespace Hypertable;
53 using namespace Tools::client;
54 using namespace std;
55 
56 namespace {
57  enum {
58  COMMAND_NONE = 0,
62  };
63 }
64 
65 int thriftbroker::CommandInterpreter::execute_line(const String &line) {
66  ParseResult parse;
67 
68  parse_line(line, parse);
69 
70  switch (parse.command) {
71 
72  case COMMAND_NONE:
73  break;
74 
75  case COMMAND_HELP:
76  if (parse.args.empty())
77  parse.args.push_back("contents");
78  display_help_text(parse.args[0]);
79  break;
80 
81  case COMMAND_SHUTDOWN:
82  try {
84  m_client->shutdown();
85  }
86  catch (ThriftGen::ClientException &e) {
87  }
88  catch (std::exception &e) {
89  }
90  break;
91 
92  case COMMAND_STATUS:
93  {
94  ThriftGen::Status status;
95  {
97  m_client->status(status);
98  }
99  if (!m_silent) {
100  cout << "ThriftBroker "
101  << Status::code_to_string(static_cast<Status::Code>(status.code));
102  if (!status.text.empty())
103  cout << " - " << status.text;
104  cout << endl;
105  }
106  return status.code;
107  }
108  break;
109 
110  default:
111  HT_FATALF("Unrecognized command - %d", (int)parse.command);
112  }
113 
114  return 0;
115 }
116 
117 
118 void thriftbroker::CommandInterpreter::ParseResult::clear() {
119  command = 0;
120  args.clear();
121  offset = 0;
122 }
123 
124 
125 void thriftbroker::CommandInterpreter::parse_line(const String &line, ParseResult &result) const {
126  string command;
127 
128  result.clear();
129 
130  boost::char_separator<char> sep(" ");
131  boost::tokenizer< boost::char_separator<char> > tokens(line, sep);
132  for (const string& arg : tokens) {
133  if (command.empty()) {
134  command = arg;
135  }
136  else if (boost::algorithm::starts_with(arg, "--seek=")) {
137  char *base = (char *)arg.c_str() + 7;
138  char *end;
139  errno = 0;
140  result.offset = strtoll(base, &end, 10);
141  if (errno != 0 || end == base) {
142  parse_error(command);
143  return;
144  }
145  }
146  else
147  result.args.push_back(arg);
148  }
149 
150  if (command.empty())
151  return;
152 
153  if (!strcasecmp(command.c_str(), "help")) {
154  result.command = COMMAND_HELP;
155  }
156  else if (!strcasecmp(command.c_str(), "shutdown")) {
157  if (result.args.empty() ||
158  (result.args.size() == 1 && !strcasecmp(result.args[0].c_str(), "now")))
159  result.command = COMMAND_SHUTDOWN;
160  else
161  parse_error(command);
162  }
163  else if (!strcasecmp(command.c_str(), "status")) {
164  if (!result.args.empty())
165  parse_error(command);
166  else
167  result.command = COMMAND_STATUS;
168  }
169  else {
170  if (m_interactive)
171  cout << "Unrecognized command - '" << command << "'" << endl;
172  else
173  HT_FATALF("Unrecognized command - '%s'", command.c_str());
174  }
175 
176 }
177 
178 
179 namespace {
180 
181  const char *g_help_text_contents[] = {
182  "shutdown .............. Shutdown ThriftBroker",
183  "status ................ Get status of ThriftBroker",
184  "",
185  "Statements must be terminated with ';'. For more information on",
186  "a specific statement, type 'help <statement>', where <statement> is from",
187  "the preceeding list.",
188  nullptr
189  };
190 
191  const char *g_help_text_shutdown[] = {
192  "shutdown [now]",
193  "",
194  " This command sends a shutdown request to the filesystem broker.",
195  " If the 'now' argument is given, the broker will do an unclean",
196  " shutdown by exiting immediately. Otherwise, it will wait for",
197  " all pending requests to complete before shutting down.",
198  nullptr
199  };
200 
201  const char *g_help_text_status[] = {
202  "status",
203  "",
204  " This command sends a status request to the filesystem broker, printing",
205  " the status output message to the console and returning the status code.",
206  " The return value of the last command issued to the interpreter will be",
207  " used as the exit status.",
208  nullptr
209  };
210 }
211 
212 void thriftbroker::CommandInterpreter::load_help_text() {
213  m_help_text["contents"] = g_help_text_contents;
214  m_help_text["shutdown"] = g_help_text_shutdown;
215  m_help_text["status"] = g_help_text_status;
216 }
217 
218 
219 void thriftbroker::CommandInterpreter::display_help_text(const std::string &command) const {
220  string lower(command);
221  boost::algorithm::to_lower(lower);
222  auto iter = m_help_text.find(lower);
223  if (iter != m_help_text.end()) {
224  const char **text = iter->second;
225  cout << endl;
226  for (size_t i=0; text[i]; i++)
227  cout << text[i] << endl;
228  cout << endl;
229  }
230  else
231  cout << endl << "No help for '" << command << "'" << endl << endl;
232 }
233 
234 void thriftbroker::CommandInterpreter::display_usage(const std::string &command) const {
235  string lower(command);
236  boost::algorithm::to_lower(lower);
237  auto iter = m_help_text.find(lower);
238  HT_ASSERT(iter != m_help_text.end());
239  const char **text = iter->second;
240  cout << "Usage: " << text[0] << endl;
241 }
242 
243 void thriftbroker::CommandInterpreter::parse_error(const std::string &command) const {
244  string lower(command);
245  boost::algorithm::to_lower(lower);
246  auto iter = m_help_text.find(lower);
247  HT_ASSERT(iter != m_help_text.end());
248  const char **text = iter->second;
249  if (m_interactive) {
250  cout << "Parse error." << endl;
251  cout << "Usage: " << text[0] << endl;
252  return;
253  }
254  else
255  HT_THROWF(Error::COMMAND_PARSE_ERROR, "Usage: %s", text[0]);
256 }
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
Declarations for Status.
STL namespace.
#define HT_ASSERT(_e_)
Definition: Logger.h:396
Declaration for ConsoleOutputSquelcher.
static const char * code_to_string(Code code)
Definition: Status.cc:39
bool status(ContextPtr &context, Timer &timer, Status &status)
Runs a status check on the master.
Definition: Utility.cc:408
Logging routines and macros.
Compatibility Macros for C/C++.
Hypertable definitions
#define HT_FATALF(msg,...)
Definition: Logger.h:343
Temporarily redirects stdout and stderr to /dev/null.
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
Error codes, Exception handling, error logging.
Declarations for CommandInterpreter.