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 
33 
34 #include <FsBroker/Lib/Utility.h>
35 
36 #include <Common/Error.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,
59  COMMAND_COPYFROMLOCAL,
60  COMMAND_COPYTOLOCAL,
63  COMMAND_LENGTH,
65  COMMAND_REMOVE,
66  COMMAND_RMDIR,
69  };
70 }
71 
72 int fsbroker::CommandInterpreter::execute_line(const String &line) {
73  ParseResult parse;
74 
75  parse_line(line, parse);
76 
77  switch (parse.command) {
78 
79  case COMMAND_NONE:
80  break;
81 
82  case COMMAND_COPYFROMLOCAL:
83  FsBroker::Lib::copy_from_local(m_client, parse.args[0], parse.args[1], parse.offset);
84  break;
85 
86  case COMMAND_COPYTOLOCAL:
87  FsBroker::Lib::copy_to_local(m_client, parse.args[0], parse.args[1], parse.offset);
88  break;
89 
90  case COMMAND_EXISTS:
91  cout << (m_client->exists(parse.args[0]) ? "true" : "false") << endl;
92  break;
93 
94  case COMMAND_HELP:
95  if (parse.args.empty())
96  parse.args.push_back("contents");
97  display_help_text(parse.args[0]);
98  break;
99 
100  case COMMAND_LENGTH:
101  cout << m_client->length(parse.args[0]) << endl;
102  break;
103 
104  case COMMAND_MKDIRS:
105  m_client->mkdirs(parse.args[0]);
106  break;
107 
108  case COMMAND_REMOVE:
109  m_client->remove(parse.args[0]);
110  break;
111 
112  case COMMAND_RMDIR:
113  m_client->rmdir(parse.args[0]);
114  break;
115 
116  case COMMAND_SHUTDOWN:
117  {
118  uint16_t flags = 0;
119  if (!parse.args.empty()) {
120  HT_ASSERT(!strcasecmp(parse.args[0].c_str(), "now"));
122  }
123  if (m_nowait)
124  m_client->shutdown(flags, 0);
125  else {
126  EventPtr event;
127  DispatchHandlerSynchronizer sync_handler;
128  m_client->shutdown(flags, &sync_handler);
129  sync_handler.wait_for_reply(event);
130  }
131  }
132  break;
133 
134  case COMMAND_STATUS:
135  {
136  Status status;
137  m_client->status(status);
138  string output;
139  Status::Code code;
140  status.get(&code, output);
141  if (!m_silent) {
142  cout << "FsBroker " << Status::code_to_string(code);
143  if (!output.empty())
144  cout << " - " << output;
145  cout << endl;
146  }
147  return static_cast<int>(code);
148  }
149 
150  default:
151  HT_FATALF("Unrecognized command - %d", (int)parse.command);
152  }
153 
154  return 0;
155 }
156 
157 
158 void fsbroker::CommandInterpreter::ParseResult::clear() {
159  command = 0;
160  args.clear();
161  offset = 0;
162 }
163 
164 
165 void fsbroker::CommandInterpreter::parse_line(const String &line, ParseResult &result) const {
166  string command;
167 
168  result.clear();
169 
170  boost::char_separator<char> sep(" ");
171  boost::tokenizer< boost::char_separator<char> > tokens(line, sep);
172  for (const string& arg : tokens) {
173  if (command.empty()) {
174  command = arg;
175  }
176  else if (boost::algorithm::starts_with(arg, "--seek=")) {
177  char *base = (char *)arg.c_str() + 7;
178  char *end;
179  errno = 0;
180  result.offset = strtoll(base, &end, 10);
181  if (errno != 0 || end == base) {
182  parse_error(command);
183  return;
184  }
185  }
186  else
187  result.args.push_back(arg);
188  }
189 
190  if (command.empty())
191  return;
192 
193  if (!strcasecmp(command.c_str(), "copyFromLocal")) {
194  if (result.args.size() != 2)
195  parse_error(command);
196  else
197  result.command = COMMAND_COPYFROMLOCAL;
198  }
199  else if (!strcasecmp(command.c_str(), "copyToLocal")) {
200  if (result.args.size() != 2)
201  parse_error(command);
202  else
203  result.command = COMMAND_COPYTOLOCAL;
204  }
205  else if (!strcasecmp(command.c_str(), "exists")) {
206  if (result.args.size() != 1)
207  parse_error(command);
208  else
209  result.command = COMMAND_EXISTS;
210  }
211  else if (!strcasecmp(command.c_str(), "help")) {
212  result.command = COMMAND_HELP;
213  }
214  else if (!strcasecmp(command.c_str(), "length")) {
215  if (result.args.size() != 1)
216  parse_error(command);
217  else
218  result.command = COMMAND_LENGTH;
219  }
220  else if (!strcasecmp(command.c_str(), "mkdirs")) {
221  if (result.args.size() != 1)
222  parse_error(command);
223  else
224  result.command = COMMAND_MKDIRS;
225  }
226  else if (!strcasecmp(command.c_str(), "rm")) {
227  if (result.args.size() != 1)
228  parse_error(command);
229  else
230  result.command = COMMAND_REMOVE;
231  }
232  else if (!strcasecmp(command.c_str(), "rmdir")) {
233  if (result.args.size() != 1)
234  parse_error(command);
235  else
236  result.command = COMMAND_RMDIR;
237  }
238  else if (!strcasecmp(command.c_str(), "shutdown")) {
239  if (result.args.empty() ||
240  (result.args.size() == 1 && !strcasecmp(result.args[0].c_str(), "now")))
241  result.command = COMMAND_SHUTDOWN;
242  else
243  parse_error(command);
244  }
245  else if (!strcasecmp(command.c_str(), "status")) {
246  if (!result.args.empty())
247  parse_error(command);
248  else
249  result.command = COMMAND_STATUS;
250  }
251  else {
252  if (m_interactive)
253  cout << "Unrecognized command - '" << command << "'" << endl;
254  else
255  HT_FATALF("Unrecognized command - '%s'", command.c_str());
256  }
257 
258 }
259 
260 
261 namespace {
262 
263  const char *g_help_text_contents[] = {
264  "copyFromLocal ......... Copy file from local filesystem to brokered filesystem",
265  "copyToLocal ........... Copy file from brokered filesystem to local filesystem",
266  "exists ................ Check for file existence",
267  "length ................ Get length of file",
268  "mkdirs ................ Create directory and missing parent directories",
269  "rm .................... Remove file",
270  "rmdir ................. Remove directory",
271  "shutdown .............. Shutdown file system broker",
272  "status ................ Get status of file system broker",
273  "",
274  "Statements must be terminated with ';'. For more information on",
275  "a specific statement, type 'help <statement>', where <statement> is from",
276  "the preceeding list.",
277  nullptr
278  };
279 
280  const char *g_help_text_copyfromlocal[] = {
281  "copyFromLocal [--seek=<offset>] <src> <dst>",
282  "",
283  " This command copies the local file <src> to the remote file <dst>",
284  " in the brokered file system. If --seek is supplied, then the source",
285  " file is seeked to offset <offset> before starting the copy.",
286  nullptr
287  };
288 
289  const char *g_help_text_copytolocal[] = {
290  "copyToLocal [--seek=<offset>] <src> <dst>",
291  "",
292  " This command copies the file <src> from the brokered file system to"
293  " the <dst> file in the local filesystem. If --seek is supplied, then",
294  " the source file is seeked to offset <offset> before starting the copy.",
295  nullptr
296  };
297 
298  const char *g_help_text_exists[] = {
299  "exists <file>",
300  "",
301  " This command checks for the existence of <file> in the brokered",
302  " filesystem and prints \"true\" if it exists, or \"false\" otherwise.",
303  nullptr
304  };
305 
306  const char *g_help_text_length[] = {
307  "length <file>",
308  "",
309  " This command fetches the length of <file> in the brokered filesystem",
310  " and prints it to the console.",
311  nullptr
312  };
313 
314  const char *g_help_text_mkdirs[] = {
315  "mkdirs <dir>",
316  "",
317  " This command creates a directory and all of its missing parents in",
318  " the broked filesystem.",
319  nullptr
320  };
321 
322  const char *g_help_text_remove[] = {
323  "rm <file>",
324  "",
325  " This command removes the file <file> in the brokered filesystem.",
326  nullptr
327  };
328 
329  const char *g_help_text_rmdir[] = {
330  "rmdir <dir>",
331  "",
332  " This command recursively removes <dir> from the brokered filesystem",
333  nullptr
334  };
335 
336  const char *g_help_text_shutdown[] = {
337  "shutdown [now]",
338  "",
339  " This command sends a shutdown request to the filesystem broker.",
340  " If the 'now' argument is given, the broker will do an unclean",
341  " shutdown by exiting immediately. Otherwise, it will wait for",
342  " all pending requests to complete before shutting down.",
343  nullptr
344  };
345 
346  const char *g_help_text_status[] = {
347  "status",
348  "",
349  " This command sends a status request to the filesystem broker, printing",
350  " the status output message to the console and returning the status code.",
351  " The return value of the last command issued to the interpreter will be",
352  " used as the exit status.",
353  nullptr
354  };
355 }
356 
357 void fsbroker::CommandInterpreter::load_help_text() {
358  m_help_text["contents"] = g_help_text_contents;
359  m_help_text["copyfromlocal"] = g_help_text_copyfromlocal;
360  m_help_text["copyToLocal"] = g_help_text_copytolocal;
361  m_help_text["exists"] = g_help_text_exists;
362  m_help_text["length"] = g_help_text_length;
363  m_help_text["mkdirs"] = g_help_text_mkdirs;
364  m_help_text["rm"] = g_help_text_remove;
365  m_help_text["rmdir"] = g_help_text_rmdir;
366  m_help_text["shutdown"] = g_help_text_shutdown;
367  m_help_text["status"] = g_help_text_status;
368 }
369 
370 
371 void fsbroker::CommandInterpreter::display_help_text(const std::string &command) const {
372  string lower(command);
373  boost::algorithm::to_lower(lower);
374  auto iter = m_help_text.find(lower);
375  if (iter != m_help_text.end()) {
376  const char **text = iter->second;
377  cout << endl;
378  for (size_t i=0; text[i]; i++)
379  cout << text[i] << endl;
380  cout << endl;
381  }
382  else
383  cout << endl << "No help for '" << command << "'" << endl << endl;
384 }
385 
386 void fsbroker::CommandInterpreter::display_usage(const std::string &command) const {
387  string lower(command);
388  boost::algorithm::to_lower(lower);
389  auto iter = m_help_text.find(lower);
390  HT_ASSERT(iter != m_help_text.end());
391  const char **text = iter->second;
392  cout << "Usage: " << text[0] << endl;
393 }
394 
395 void fsbroker::CommandInterpreter::parse_error(const std::string &command) const {
396  string lower(command);
397  boost::algorithm::to_lower(lower);
398  auto iter = m_help_text.find(lower);
399  HT_ASSERT(iter != m_help_text.end());
400  const char **text = iter->second;
401  if (m_interactive) {
402  cout << "Parse error." << endl;
403  cout << "Usage: " << text[0] << endl;
404  return;
405  }
406  else
407  HT_THROWF(Error::COMMAND_PARSE_ERROR, "Usage: %s", text[0]);
408 }
Holds Nagios-style program status information.
Definition: Status.h:42
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
std::shared_ptr< Event > EventPtr
Smart pointer to Event.
Definition: Event.h:228
STL namespace.
void copy_to_local(ClientPtr &client, const std::string &from, const std::string &to, int64_t offset=0)
Definition: Utility.cc:150
bool wait_for_reply(EventPtr &event)
This method is used by a client to synchronize.
Code
Enumeration for status codes.
Definition: Status.h:47
#define HT_ASSERT(_e_)
Definition: Logger.h:396
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
Declarations for CommandInterpreter.
Compatibility Macros for C/C++.
Hypertable definitions
#define HT_FATALF(msg,...)
Definition: Logger.h:343
DispatchHandler class used to synchronize with response messages.
void copy_from_local(ClientPtr &client, const std::string &from, const std::string &to, int64_t offset=0)
Definition: Utility.cc:100
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
void get(Code *code, std::string &text) const
Gets status code and text.
Definition: Status.h:111
Declarations of utility functions.
Declarations for HqlHelpText.
Error codes, Exception handling, error logging.