0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
HsCommandInterpreter.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.
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 
22 #include <Common/Compat.h>
23 
24 #include "HsCommandInterpreter.h"
25 #include "HsHelpText.h"
26 #include "HsParser.h"
27 #include "DirEntry.h"
28 #include "DirEntryAttr.h"
29 #include "FileHandleCallback.h"
30 
31 #include <Common/Error.h>
32 #include <Common/FileUtils.h>
33 #include <Common/Stopwatch.h>
34 #include <Common/DynamicBuffer.h>
35 
36 #include <boost/algorithm/string.hpp>
37 
38 extern "C" {
39 #if defined(__sun__)
40 #include <inttypes.h>
41 #endif
42 }
43 
44 #include <cassert>
45 #include <cstdio>
46 #include <cstring>
47 #include <fstream>
48 #include <iostream>
49 
50 using namespace std;
51 using namespace Hyperspace;
52 using namespace HsParser;
53 
54 
55 HsCommandInterpreter::HsCommandInterpreter(Session* session)
56  : m_session(session) {
57 }
58 
59 
61  String out_str;
62  ParserState state;
63  Parser parser(state);
64  parse_info<> info;
65 
66  info = parse(line.c_str(), parser, space_p);
67 
68  if (info.full) {
69 
70  if (state.command == COMMAND_MKDIR) {
71  String fname = state.dir_name;
72  m_session->mkdir(fname);
73  }
74  else if (state.command == COMMAND_MKDIRS) {
75  String fname = state.dir_name;
76  m_session->mkdirs(fname);
77  }
78  else if (state.command == COMMAND_DELETE) {
79  String fname = state.node_name;
80  m_session->unlink(fname);
81  }
82 
83  else if (state.command == COMMAND_OPEN) {
84  ::uint64_t handle;
85  int event_mask = state.event_mask;
86  int open_flag = state.open_flag;
87  String fname = state.node_name;
88 
89  if(open_flag == 0) // read is default
90  open_flag = OPEN_FLAG_READ;
91 
92  if(fname == "")
94  "Error: no filename supplied.");
95 
96  HandleCallbackPtr callback = make_shared<FileHandleCallback>(event_mask);
97  handle = m_session->open(fname,open_flag,callback);
98 
99  // store opened handle in global HsClientState namespace
100  String normal_name;
101  Util::normalize_pathname(fname,normal_name);
102  HsClientState::file_map[normal_name] = handle;
103  }
104 
105  else if (state.command == COMMAND_CREATE) {
106  ::uint64_t handle;
107  int event_mask = state.event_mask;
108  int open_flag = state.open_flag;
109  String fname = state.file_name;
110 
111  if(open_flag == 0)
113  "Error: no flags supplied.");
114  else if (fname == "")
116  "Error: no filename supplied.");
117 
118  HandleCallbackPtr callback = make_shared<FileHandleCallback>(event_mask);
119  handle = m_session->create(fname,open_flag,callback,state.attrs);
120 
121  // store opened handle in global HsClientState namespace
122  String normal_name;
123  Util::normalize_pathname(fname,normal_name);
124  HsClientState::file_map[normal_name] = handle;
125  }
126 
127  else if (state.command == COMMAND_CLOSE) {
128  ::uint64_t handle;
129  String fname = state.node_name;
130  handle = Util::get_handle(fname);
131  String normal_name;
132  Util::normalize_pathname(fname,normal_name);
133  HsClientState::file_map.erase(normal_name);
134  m_session->close(handle);
135  }
136 
137  else if (state.command == COMMAND_ATTRSET) {
138  ::uint64_t handle = 0;
139  int size = state.last_attr_size;
140  String name = state.last_attr_name;
141  String value = state.last_attr_value;
142  String fname = state.node_name;
143  const char *val = value.c_str();
144 
145  try {
146  handle = Util::get_handle(fname);
147  m_session->attr_set(handle, name, val, size);
148  }
149  catch (Exception &e) {
150  String normalized_fname;
151  Util::normalize_pathname(fname, normalized_fname);
152  m_session->attr_set(normalized_fname, name, val, size);
153  }
154  }
155 
156  else if (state.command == COMMAND_ATTRGET) {
157  ::uint64_t handle;
158  String name = state.last_attr_name;
159  String fname = state.node_name;
160  DynamicBuffer value(0);
161 
162  try {
163  handle = Util::get_handle(fname);
164  m_session->attr_get(handle, name, value);
165  }
166  catch (Exception &e) {
167  String normalized_fname;
168  Util::normalize_pathname(fname, normalized_fname);
169  m_session->attr_get(normalized_fname, name, value);
170  }
171 
172  String valstr = String((const char*)(value.base),value.fill());
173  cout << valstr << endl;
174  }
175 
176  else if (state.command == COMMAND_ATTRINCR) {
177  ::uint64_t handle;
178  String name = state.last_attr_name;
179  String fname = state.node_name;
180  uint64_t attr_val;
181 
182  try {
183  handle = Util::get_handle(fname);
184  attr_val = m_session->attr_incr(handle, name);
185  }
186  catch (Exception &e) {
187  String normalized_fname;
188  Util::normalize_pathname(fname, normalized_fname);
189  attr_val = m_session->attr_incr(normalized_fname, name);
190  }
191 
192  cout << attr_val << endl;
193  }
194 
195  else if (state.command == COMMAND_ATTREXISTS) {
196  ::uint64_t handle = 0;
197  String name = state.last_attr_name;
198  String fname = state.node_name;
199  bool exists;
200 
201  try {
202  handle = Util::get_handle(fname);
203  exists = m_session->attr_exists(handle, name);
204  }
205  catch (Exception &e) {
206  String normalized_fname;
207  Util::normalize_pathname(fname, normalized_fname);
208  exists = m_session->attr_exists(normalized_fname, name);
209  }
210 
211  if (exists)
212  cout << "true" << endl;
213  else
214  cout << "false" << endl;
215  }
216 
217  else if (state.command == COMMAND_ATTRLIST) {
218  ::uint64_t handle;
219  String fname = state.node_name;
220  vector<String> attrs;
221 
222  handle = Util::get_handle(fname);
223 
224  m_session->attr_list(handle, attrs);
225 
226  for (vector<String>::iterator it = attrs.begin(); it != attrs.end(); ++it) {
227  cout << *it << endl;
228  }
229  }
230 
231  else if (state.command == COMMAND_ATTRDEL) {
232  ::uint64_t handle;
233  String name = state.last_attr_name;
234  String fname = state.node_name;
235 
236  handle = Util::get_handle(fname);
237 
238  m_session->attr_del(handle, name);
239  }
240 
241  else if (state.command == COMMAND_EXISTS) {
242  String fname = state.node_name;
243 
244  if(m_session->exists(fname)) {
245  cout<< "true" << endl;
246  }
247  else {
248  cout << "false" << endl;
250  }
251  }
252 
253  else if (state.command == COMMAND_READDIR) {
254  ::uint64_t handle;
255  vector<struct DirEntry> listing;
256  String fname = state.dir_name;
257 
258  handle = Util::get_handle(fname);
259  m_session->readdir(handle, listing);
260 
261  struct LtDirEntry ascending;
262  sort(listing.begin(), listing.end(), ascending);
263  for (size_t ii=0; ii<listing.size(); ii++) {
264  if (listing[ii].is_dir)
265  cout << "(dir) ";
266  else
267  cout << " ";
268  cout << listing[ii].name << endl ;
269  }
270  cout << flush ;
271  }
272 
273  else if (state.command == COMMAND_READDIRATTR) {
274  ::uint64_t handle;
275  vector<DirEntryAttr> listing;
276  String fname = state.dir_name;
277  String name = state.last_attr_name;
278 
279  handle = Util::get_handle(fname);
280  m_session->readdir_attr(handle, name, state.recursive, listing);
281 
282  struct LtDirEntryAttr ascending;
283  sort(listing.begin(), listing.end(), ascending);
284  printDirEntryAttrListing(0, name, listing);
285  }
286 
287  else if (state.command == COMMAND_READPATHATTR) {
288  ::uint64_t handle;
289  vector<DirEntryAttr> listing;
290  String fname = state.dir_name;
291  String name = state.last_attr_name;
292 
293  handle = Util::get_handle(fname);
294  m_session->readpath_attr(handle, name, listing);
295 
296  struct LtDirEntryAttr ascending;
297  sort(listing.begin(), listing.end(), ascending);
298  printDirEntryAttrListing(0, name, listing);
299  }
300 
301  else if (state.command == COMMAND_DUMP) {
302  ::uint64_t handle;
303  String fname;
304  String outfile = state.outfile;
305  String slash("/");
306  vector<String> dirs;
307  String last_component;
308  ostream *oo;
309  DynamicBuffer value(0);
310  String value_str;
311  String display_fname;
312  String escaped_double_quote("\\\"");
313  String unescaped_double_quote(1, '"');
314  String escaped_single_quote("\\\'");
315  String unescaped_single_quote("'");
316  String escaped_newline("\\n\n");
317  String unescaped_newline(1,'\n');
318 
319  String lock_attr("lock.generation");
320  String generation_attr("generation");
321 
322  dirs.push_back(state.dir_name);
323  if (!outfile.empty()) {
325  oo = new ofstream(state.outfile.c_str(), ios_base::out);
326  }
327  else
328  oo = &cout;
329 
330  while (!dirs.empty()) {
331  Util::normalize_pathname(dirs.back(), fname);
332  if (fname.size()==0)
333  display_fname = "/";
334  else
335  display_fname = fname;
336  dirs.pop_back();
337  vector<struct DirEntry> listing;
338  vector<String> attrs;
339  vector<String> tmp_dirs;
340  HandleCallbackPtr null_callback;
341  bool has_newline=false;
342 
343  handle = m_session->open(fname, OPEN_FLAG_READ, null_callback);
344 
345  if (state.as_commands) {
346  *oo << "MKDIRS " << display_fname << ";" << endl;
347  *oo << "OPEN " << display_fname << " FLAGS=READ|WRITE|CREATE ;" << endl;
348  }
349  else
350  *oo << display_fname << "\t" << endl;
351  // read all attrs of this dir
352  attrs.clear();
353  m_session->attr_list(handle, attrs);
354 
355  for (const auto &attr : attrs) {
356  if (attr == lock_attr || attr == generation_attr)
357  continue;
358  value.clear();
359  m_session->attr_get(handle, attr, value);
360  value_str = String((const char *)value.base, value.fill());
361 
362  boost::algorithm::replace_all(value_str, unescaped_double_quote, escaped_double_quote);
363  boost::algorithm::replace_all(value_str, unescaped_single_quote, escaped_single_quote);
364  has_newline = false;
365  if (value_str.find("\n") != String::npos)
366  has_newline = true;
367  //boost::algorithm::replace_all(value_str, unescaped_newline, escaped_newline);
368 
369  if (state.as_commands) {
370  *oo << "ATTRSET " << display_fname << " " << attr << "=\"" << value_str << "\"";
371  if (has_newline)
372  *oo << "\n";
373  *oo << ";" << endl;
374  }
375  else
376  *oo << display_fname << ":" << attr << "\t" << value_str << endl;
377  }
378 
379  // read all files and dirs under this path; skip BAD_PATHNAME errors.
380  // they simply mean that the path is a file and not a directory
381  try {
382  m_session->readdir(handle, listing);
383  }
384  catch (Exception &e) {
386  throw;
387  else
388  continue;
389  }
390  for (const auto &entry : listing) {
391  // if dir save it
392  if(entry.is_dir)
393  tmp_dirs.push_back(fname + "/" + entry.name);
394  // if file get all get all info
395  else {
396  String file;
397  Util::normalize_pathname(fname + "/" + entry.name, file);
398 
399  if (state.as_commands)
400  *oo << "OPEN " << file << " FLAGS=READ|WRITE|CREATE ;" << endl;
401  else
402  *oo << file << "\t" << endl;
403  handle = m_session->open(file, OPEN_FLAG_READ, null_callback);
404  attrs.clear();
405  m_session->attr_list(handle, attrs);
406 
407  for (const auto &attr : attrs) {
408  if (attr == lock_attr || attr == generation_attr)
409  continue;
410  value.clear();
411  m_session->attr_get(handle, attr, value);
412  value_str = String((const char *)value.base, value.fill());
413  boost::algorithm::replace_all(value_str, unescaped_double_quote, escaped_double_quote);
414  boost::algorithm::replace_all(value_str, unescaped_single_quote, escaped_single_quote);
415  has_newline = false;
416  if (value_str.find("\n") != String::npos)
417  has_newline = true;
418  //boost::algorithm::replace_all(value_str, unescaped_newline, escaped_newline);
419 
420  if (state.as_commands) {
421  *oo << "ATTRSET " << file << " " << attr << "=\"" << value_str << "\"";
422  if (has_newline)
423  *oo << "\n";
424  *oo << ";" << endl;
425  }
426  else
427  *oo << file << ":" << attr << "\t" << value_str << endl;
428  }
429  }
430  }
431 
432  if (tmp_dirs.size())
433  for(int ii=tmp_dirs.size()-1; ii>=0; --ii)
434  dirs.push_back(tmp_dirs[ii]);
435  }
436  }
437 
438  else if (state.command == COMMAND_LOCK) {
439  ::uint64_t handle;
440  LockMode mode = (LockMode)state.lock_mode;
441  String fname = state.node_name;
442  struct LockSequencer lockseq;
443 
444  handle = Util::get_handle(fname);
445 
446  m_session->lock(handle, mode, &lockseq);
447 
448  cout << "SEQUENCER name=" << lockseq.name << " mode=" << lockseq.mode
449  << " generation=" << lockseq.generation << endl;
450  }
451 
452  else if (state.command == COMMAND_TRYLOCK) {
453  ::uint64_t handle;
454  LockMode mode = (LockMode)state.lock_mode;
455  String fname = state.node_name;
456  struct LockSequencer lockseq;
458 
459  handle = Util::get_handle(fname);
460  m_session->try_lock(handle, mode, &status, &lockseq);
461 
463  cout << "SEQUENCER name=" << lockseq.name << " mode=" << lockseq.mode
464  << " generation=" << lockseq.generation << endl;
465  else if (status == LOCK_STATUS_BUSY)
466  cout << "busy" << endl;
467  else
468  cout << "Unknown status: " << status << endl;
469 
470  }
471 
472  else if (state.command == COMMAND_RELEASE) {
473  ::uint64_t handle;
474  String fname = state.node_name;
475 
476  handle = Util::get_handle(fname);
477 
478  m_session->release(handle);
479  }
480 
481  else if (state.command == COMMAND_GETSEQ) {
482  ::uint64_t handle;
483  struct LockSequencer lockseq;
484  String fname = state.node_name;
485 
486  handle = Util::get_handle(fname);
487 
488  m_session->get_sequencer(handle, &lockseq);
489 
490  cout << "SEQUENCER name=" << lockseq.name << " mode=" << lockseq.mode
491  << " generation=" << lockseq.generation << endl;
492  }
493 
494  else if (state.command == COMMAND_ECHO) {
495  String str = state.str;
496 
497  cout << str << endl;
498  }
499 
500  else if (state.command == COMMAND_LOCATE) {
501  int type = state.locate_type;
502  String result = m_session->locate(type);
503  cout << result << endl;
504  }
505 
506  else if (state.command == COMMAND_STATUS) {
507  Status status;
508  Status::Code code;
509  int32_t error = m_session->status(status);
510  if (error == Error::OK) {
511  string text;
512  status.get(&code, text);
513  if (!m_silent) {
514  cout << "Hyperspace " << Status::code_to_string(code);
515  if (!text.empty())
516  cout << " - " << text;
517  cout << endl;
518  }
519  }
520  else {
521  if (!m_silent)
522  cout << "Hyperspace CRITICAL - " << Error::get_text(error) << endl;
523  code = Status::Code::CRITICAL;
524  }
525  return static_cast<int>(code);
526  }
527 
528  else if (state.command == COMMAND_HELP) {
529  const char **text = HsHelpText::get(state.help_str);
530 
531  if (text) {
532  for (size_t i=0; text[i]; i++)
533  cout << text[i] << endl;
534  }
535  else
536  cout << endl << "no help for '" << state.help_str << "'\n" << endl;
537  }
538 
539  else
540  HT_THROW(Error::HYPERSPACE_CLI_PARSE_ERROR, "unsupported command: "
541  + line);
542  }
543  else
544  HT_THROWF(Error::HYPERSPACE_CLI_PARSE_ERROR, "parse error at: %s",
545  info.stop);
546  return 0;
547 }
548 
549 void HsCommandInterpreter::printDirEntryAttrListing(int indent, const String& attr_name, const std::vector<DirEntryAttr> listing) {
550  static const int indent_size = 2;
551  for (size_t ii=0; ii<listing.size(); ii++) {
552  if (listing[ii].is_dir)
553  cout << "(dir) ";
554  else
555  cout << " ";
556  if (indent) cout << String(indent - indent_size, ' ') << "+" << String(indent_size - 1, ' ');
557  if (listing[ii].has_attr) {
558  String attr_val((const char*)listing[ii].attr.base);
559  cout << listing[ii].name << ", " << attr_name << "=" << attr_val << endl ;
560  }
561  else
562  cout << listing[ii].name << endl ;
563 
564  printDirEntryAttrListing(indent + indent_size, attr_name, listing[ii].sub_entries);
565  }
566  cout << flush ;
567 }
Lock successfully granted.
Definition: LockSequencer.h:58
void attr_get(uint64_t handle, const std::string &attr, DynamicBuffer &value, Timer *timer=0)
Gets an extended attribute of a file.
Definition: Session.cc:554
void readdir(uint64_t handle, std::vector< DirEntry > &listing, Timer *timer=0)
Gets a directory listing.
Definition: Session.cc:817
uint64_t open(const std::string &name, uint32_t flags, HandleCallbackPtr &callback, Timer *timer=0)
Opens a file.
Definition: Session.cc:210
void attr_list(uint64_t handle, vector< String > &anames, Timer *timer=0)
Lists all extended attributes of a file.
Definition: Session.cc:775
Holds Nagios-style program status information.
Definition: Status.h:42
void close(uint64_t handle, Timer *timer=0)
Closes a file handle.
Definition: Session.cc:255
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
void lock(uint64_t handle, LockMode mode, LockSequencer *sequencerp, Timer *timer=0)
Locks a file.
Definition: Session.cc:968
The Stopwatch measures elapsed time.
int execute_line(const String &line) override
std::vector< Attribute > attrs
Definition: HsParser.h:108
Exclusive lock attempt failed because another has it locked.
Definition: LockSequencer.h:60
static const char ** get(const std::string &subject)
Definition: HsHelpText.cc:267
Po::typed_value< String > * str(String *v=0)
Definition: Properties.h:166
void readpath_attr(uint64_t handle, const std::string &attr, std::vector< DirEntryAttr > &listing, Timer *timer=0)
Gets a listing of the value of a specified atribute for each path components of the file/dir name...
Definition: Session.cc:916
uint64_t get_handle(std::string name)
LockStatus
Lock status.
Definition: LockSequencer.h:56
STL namespace.
int status(Status &status, Timer *timer=0)
Check the status of the Hyperspace master server.
Definition: Session.cc:1162
A dynamic, resizable and reference counted memory buffer.
Definition: DynamicBuffer.h:42
Code
Enumeration for status codes.
Definition: Status.h:47
Hyperspace definitions
static const char * code_to_string(Code code)
Definition: Status.cc:39
uint64_t create(const std::string &name, uint32_t flags, HandleCallbackPtr &callback, const std::vector< Attribute > &init_attrs, Timer *timer=0)
Creates a file.
Definition: Session.cc:235
File system utility functions.
static void printDirEntryAttrListing(int indent, const String &attr_name, const std::vector< DirEntryAttr > listing)
A dynamic, resizable memory buffer.
void readdir_attr(uint64_t handle, const std::string &attr, bool include_sub_entries, std::vector< DirEntryAttr > &listing, Timer *timer=0)
Gets a listing of all entries in a directory which have a certain attribute .
Definition: Session.cc:864
void normalize_pathname(std::string name, std::string &normal_name)
const char * get_text(int error)
Returns a descriptive error message.
Definition: Error.cc:330
bool status(ContextPtr &context, Timer &timer, Status &status)
Runs a status check on the master.
Definition: Utility.cc:408
bool exists(const std::string &name, Timer *timer=0)
Checks for the existence of a file.
Definition: Session.cc:335
void release(uint64_t handle, Timer *timer=0)
Releases any file handle locks.
Definition: Session.cc:1088
void attr_set(uint64_t handle, const std::string &attr, const void *value, size_t value_len, Timer *timer=0)
Sets an extended attribute of a file.
Definition: Session.cc:369
String locate(int type)
Returns location of Hyperspace Master/Replicas.
Definition: Session.cc:1145
bool attr_exists(uint64_t handle, const std::string &attr, Timer *timer=0)
Definition: Session.cc:685
Compatibility Macros for C/C++.
void attr_del(uint64_t handle, const std::string &name, Timer *timer=0)
Deletes an extended attribute of a file.
Definition: Session.cc:747
void get_sequencer(uint64_t handle, LockSequencer *sequencerp, Timer *timer=0)
Gets the lock sequencer of a locked file or directory handle.
Definition: Session.cc:1120
uint32_t mode
lock mode (LOCK_MODE_SHARED or LOCK_MODE_EXCLUSIVE)
Definition: LockSequencer.h:40
uint64_t attr_incr(uint64_t handle, const std::string &attr, Timer *timer=0)
Atomically increments the attribute and returns pre-incremented value Attribute is assumed to be a ui...
Definition: Session.cc:485
static bool expand_tilde(String &fname)
Expands a leading tilde character in a filename.
Definition: FileUtils.cc:472
std::shared_ptr< HandleCallback > HandleCallbackPtr
Hyperspace session.
Definition: Session.h:148
void try_lock(uint64_t handle, LockMode mode, LockStatus *statusp, LockSequencer *sequencerp, Timer *timer=0)
Attempts to lock a file.
Definition: Session.cc:1035
void unlink(const std::string &name, Timer *timer=0)
Removes a file or directory.
Definition: Session.cc:308
LockMode
Lock mode.
Definition: LockSequencer.h:47
void clear()
Clears the buffer.
std::string name
Pathname of file that is locked.
Definition: LockSequencer.h:38
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
uint8_t * base
Pointer to the allocated memory buffer.
void get(Code *code, std::string &text) const
Gets status code and text.
Definition: Status.h:111
size_t fill() const
Returns the size of the used portion.
Definition: DynamicBuffer.h:70
This is a generic exception class for Hypertable.
Definition: Error.h:314
void mkdir(const std::string &name, Timer *timer=0)
Creates a directory.
Definition: Session.cc:295
Definition: DirEntry.h:41
Open file for reading.
Definition: Session.h:71
void mkdirs(const std::string &name, Timer *timer=0)
Creates a directory, including all intermediate paths.
Definition: Session.cc:299
Error codes, Exception handling, error logging.
#define HT_THROW(_code_, _msg_)
Definition: Error.h:478
int code() const
Returns the error code.
Definition: Error.h:391
Definition: DirEntryAttr.h:71