SWC-DB  v0.5.12 C++ documentations
SWC-DB© (Super Wide Column Database) - High Performance Scalable Database (https://github.com/kashirin-alex/swc-db)
Settings.cc
Go to the documentation of this file.
1 /*
2  * SWC-DB© Copyright since 2019 Alex Kashirin <kashirin.alex@gmail.com>
3  * License details at <https://github.com/kashirin-alex/swc-db/#license>
4  */
5 
6 
7 #include "swcdb/Version.h"
9 
10 #include <fstream>
11 #include <filesystem>
12 
13 
14 #if defined(SWC_PATH_ETC)
15 #define USE_SWC_PATH_ETC(_) SWC_PATH_ETC
16 #else
17 #define USE_SWC_PATH_ETC(_default_) _default_
18 #endif
19 
20 #if defined(SWC_PATH_LOG)
21 #define USE_SWC_PATH_LOG(_) SWC_PATH_LOG
22 #else
23 #define USE_SWC_PATH_LOG(_default_) _default_
24 #endif
25 
26 #if defined(SWC_PATH_RUN)
27 #define USE_SWC_PATH_RUN(_) SWC_PATH_RUN
28 #else
29 #define USE_SWC_PATH_RUN(_default_) _default_
30 #endif
31 
32 
33 
34 namespace SWC { namespace Config {
35 
36 SWC_SHOULD_NOT_INLINE
38  : cmdline_desc(true),
39  file_desc(true),
40  install_path(),
41  executable(),
42  m_cmd_args(),
43  m_dyn_files() {
45 }
46 
47 Settings::~Settings() noexcept { }
48 
49 SWC_SHOULD_NOT_INLINE
50 void Settings::init(int argc, char *argv[],
53  {
54  std::error_code ec;
55  auto path = std::filesystem::read_symlink("/proc/self/exe", ec);
56  if(ec) {
57  std::cerr << "Problem reading file='/proc/self/exe' ";
58  Error::print(std::cerr, ec.value());
59  std::cerr << std::endl;
60  SWC_QUICK_EXIT(EXIT_FAILURE);
61  }
62 
63  executable = path.filename().string();
64  install_path = (path.parent_path().has_parent_path()
65  ? path.parent_path() : path).parent_path().string();
66  }
67 
68  init_options();
69 
71  init_app_options(this);
72 
73  parse_args(argc, argv);
74 
76  init_post_cmd_args(this);
77 
78  {
79  auto verbose = get<Property::Value_bool_g>("verbose");
80  if(verbose->get() && get_bool("quiet")) {
81  verbose->set(false);
82  }
83  }
84 
85  if(!get_bool("quiet") && !has("daemon")) {
87  }
88 
89  {
90  auto loglevel = get<Property::Value_enum_g>("swc.logging.level");
91  if(get_bool("debug")) {
92  loglevel->set(LOG_DEBUG);
93  } else if(loglevel->get() == -1) {
95  << "unknown logging level: "<< loglevel->to_string();
96  );
97  SWC_QUICK_EXIT(EXIT_SUCCESS);
98  }
99  }
100 }
101 
102 SWC_SHOULD_NOT_INLINE
104 
106  ("help,h", "Show this help message and exit")
107  ("help-config", "Show help message for config properties")
108  ("version,v", "Show version information and exit")
109 
110  ("verbose", g_boo(false)->zero_token(), "Show more verbose output")
111  ("debug", boo(false)->zero_token(), "Shortcut to --swc.logging.level debug")
112  ("quiet", boo(false)->zero_token(), "Negate verbose")
113  ("daemon ", boo()->zero_token(), "Start process in background mode")
114 
115  ("swc.cfg.path",
116  str(USE_SWC_PATH_ETC(install_path+"/etc/swcdb/")),
117  "Path of configuration files")
118 
119  ("swc.cfg", str("swc.cfg"), "Main configuration file")
120  ("swc.cfg.dyn", strs(), "Main dynamic configuration file")
121 
122  ("swc.logging.level,l",
123  g_enum(
124  LOG_INFO,
125  [](int value) noexcept { Core::logger.set_level(value); },
128  ),
129  "Logging level: debug|info|notice|warn|error|crit|alert|fatal")
130  ("swc.logging.path",
131  str(USE_SWC_PATH_LOG(install_path + "/var/log/swcdb/")),
132  "Path of log files")
133 
134  //("induce-failure", str(), "Arguments for inducing failure")
135  /* Interactive-Shell options
136  ("silent", boo()->zero_token(),
137  "as Not Interactive or Show as little output as possible")
138  */
139  ;
140 }
141 
142 SWC_SHOULD_NOT_INLINE
143 void Settings::parse_args(int argc, char *argv[]) {
144  {
145  Parser prs(false);
146  prs.config.add(cmdline_desc);
147  prs.config.add(file_desc);
148  prs.parse_cmdline(argc, argv);
149 
150  prs.own_options(m_cmd_args);
151 
153  }
154 
155  // some built-in behavior
156  if (has("help")) {
158  SWC_QUICK_EXIT(EXIT_SUCCESS);
159  }
160 
161  if (has("help-config")) {
163  SWC_QUICK_EXIT(EXIT_SUCCESS);
164  }
165 
166  if (has("version")) {
167  SWC_PRINT << swcdb_version() << '\n'
169  SWC_QUICK_EXIT(EXIT_SUCCESS);
170  }
171 
172  if(has("swc.cfg"))
173  parse_file(get_str("swc.cfg"), "swc.cfg.dyn");
174 }
175 
176 SWC_SHOULD_NOT_INLINE
177 void Settings::parse_file(const std::string& name, const char* onchg) {
178  if(name.empty())
179  return;
180 
181  std::filesystem::path fname;
182  if(name.front() != '/' && name.front() != '.')
183  fname = get_str("swc.cfg.path");
184  fname.concat(name);
185  {
186  std::error_code ec;
187  if(!std::filesystem::exists(fname, ec))
188  SWC_THROWF(ENOENT, "cfg file=%s not found", fname.string().c_str());
189  }
190  load(fname.string(), file_desc, cmdline_desc, false);
191  load_files_by(onchg, false);
192  load_from(m_cmd_args); // Inforce cmdline properties
193 }
194 
195 SWC_SHOULD_NOT_INLINE
196 void Settings::load_files_by(const char* fileprop, bool allow_unregistered) {
197  if(!fileprop || !has(fileprop))
198  return;
199  Strings files;
200  {
201  auto ptr = get<Property::Value_strings>(fileprop);
202  if(!ptr)
203  return;
204  files = ptr->get();
205  }
206  for(auto it=files.cbegin(); it != files.cend(); ++it) {
207  std::string fname;
208  if(it->front() != '/' && it->front() != '.')
209  fname.append(get_str("swc.cfg.path"));
210  fname.append(*it);
211 
212  try {
213  load(fname, file_desc, cmdline_desc, allow_unregistered);
214 
216  auto it_found = std::find(
217  m_dyn_files.cbegin(), m_dyn_files.cend(), fname);
218  if(it_found == m_dyn_files.cend())
219  m_dyn_files.emplace_back(std::move(fname));
220  } catch(...) {
223  << fileprop << " has bad cfg file='" << *it << "': " << e;
224  );
225  }
226  }
227 }
228 
229 namespace {
230 
231 SWC_SHOULD_NOT_INLINE
232 void write_pid(const std::filesystem::path& pid_file, size_t pid) {
233  errno = 0;
234  {
235  std::ofstream pid_file_buff(pid_file, std::ios::out);
236  if(pid_file_buff.is_open()) {
237  pid_file_buff << std::to_string(pid);
238  pid_file_buff.close();
239  }
240  }
241  if(errno) {
242  std::cerr << "Problem writing pid-file=" << pid_file;
243  Error::print(std::cerr << ' ', errno);
244  std::cerr << std::endl;
245  SWC_QUICK_EXIT(EXIT_FAILURE);
246  }
247 }
248 
249 SWC_SHOULD_NOT_INLINE
250 std::string get_old_pid(const std::filesystem::path& pid_file) {
251  std::string old_pid;
252  std::error_code ec;
253  if(std::filesystem::exists(pid_file, ec)) {
254  errno = 0;
255  std::ifstream buffer(pid_file);
256  if(buffer.is_open()) {
257  buffer >> old_pid;
258  buffer.close();
259  }
260  if(old_pid.empty())
261  ec = std::error_code(errno?errno:ECANCELED, std::generic_category());
262  }
263  if(ec) {
264  std::cerr << "Problem reading pid-file=" << pid_file;
265  Error::print(std::cerr << ' ', ec.value());
266  std::cerr << std::endl;
267  SWC_QUICK_EXIT(EXIT_FAILURE);
268  }
269  return old_pid;
270 }
271 
272 SWC_SHOULD_NOT_INLINE
273 void check_pid(const std::filesystem::path& pid_file,
274  const std::string& install_path,
275  const std::string& executable) {
276  auto old_pid = get_old_pid(pid_file);
277  if(old_pid.empty())
278  return;
279  std::filesystem::path pid_exe("/proc/");
280  pid_exe.concat(old_pid);
281  pid_exe.concat("/exe");
282  std::error_code ec;
283  if(std::filesystem::exists(pid_exe, ec)) {
284  auto path = std::filesystem::read_symlink(pid_exe, ec);
285  if(!ec) {
286  std::filesystem::path prog(install_path + "/bin/" + executable);
287  if(!Condition::str_cmp(path.string().c_str(), prog.string().c_str(),
288  prog.string().size())) { // incl. " (deleted)"
289  std::cerr << "Problem executing '" << executable
290  << "', process already running-pid=" << old_pid
291  << ", stop it first" << std::endl;
292  SWC_QUICK_EXIT(EXIT_FAILURE);
293  }
294  }
295  }
296  if(ec) {
297  std::cerr << "Problem reading running-pid='" << pid_exe << "' ";
298  Error::print(std::cerr, ec.value());
299  std::cerr << std::endl;
300  SWC_QUICK_EXIT(EXIT_FAILURE);
301  }
302  std::filesystem::remove(pid_file, ec);
303 }
304 
305 SWC_SHOULD_NOT_INLINE
306 void update_pid(const std::string& install_path,
307  const std::string& executable,
308  uint16_t port,
309  size_t pid) {
310  std::filesystem::path pid_file(USE_SWC_PATH_RUN(install_path + "/run/"));
311  pid_file.concat(executable);
312  if(port) {
313  pid_file.concat(".");
314  pid_file.concat(std::to_string(port));
315  }
316  pid_file.concat(".pid");
317 
318  check_pid(pid_file, install_path, executable);
319  write_pid(pid_file, pid);
320 
321  std::cout << "Executing '"<< executable
322  << "' with pid-file=" << pid_file << std::endl;
323 }
324 
325 SWC_SHOULD_NOT_INLINE
326 void print_init(const Settings* settings) {
327  SWC_LOG_OUT(
328  LOG_NOTICE,
329  settings->print(SWC_LOG_OSTREAM
330  << "Initialized " << settings->executable << ' '
331  << swcdb_version() << '\n'
332  << swcdb_copyrights() << '\n'
333  << "Process Settings: \n");
334  );
335 }
336 
337 }
338 
339 SWC_SHOULD_NOT_INLINE
340 void Settings::init_process(bool with_pid_file, const char* port_cfg) {
341  bool daemon = has("daemon");
342  #if defined(__MINGW64__) || defined(_WIN32)
343  daemon = false;
344  #define fork() false
345  #endif
346 
347  if(daemon && fork())
348  SWC_QUICK_EXIT(EXIT_SUCCESS);
349 
350  size_t pid = getpid();
351  if(with_pid_file) {
352  update_pid(
353  install_path,
354  executable,
355  port_cfg && !defaulted(port_cfg) ? get_i16(port_cfg) : 0,
356  pid
357  );
358  }
359 
360  executable.append(".");
361  executable.append(std::to_string(pid));
362 
364  if(daemon)
365  Core::logger.daemon(get_str("swc.logging.path"));
366 
367  if(daemon || get_gbool("verbose"))
368  print_init(this);
369 }
370 
371 std::string Settings::usage_str(const char* usage) {
372  std::string tmp(swcdb_copyrights());
373  tmp += '\n';
374  if(!usage)
375  tmp.append(format("Usage: %s [options]\n\nOptions:", executable.c_str()));
376  else if(strstr(usage, "%s"))
377  tmp.append(format_unsafe(usage, executable.c_str()));
378  else
379  tmp.append(usage);
380  return tmp;
381 }
382 
383 
384 namespace {
385 
386 SWC_SHOULD_NOT_INLINE
387 time_t file_mtime(const char* filename) {
388  errno = 0;
389  struct stat statbuf;
390  if(::stat(filename, &statbuf)) {
391  SWC_LOGF(LOG_WARN, "cfg-file '%s' err(%s)",
392  filename, Error::get_text(errno));
393  return 0;
394  }
395  return statbuf.st_mtime;
396 }
397 }
398 
399 SWC_SHOULD_NOT_INLINE
401  try {
403  for(auto& dyn : m_dyn_files) {
404  time_t mtime = file_mtime(dyn.filename.c_str());
405  if(mtime && dyn.modified != mtime) {
406  dyn.modified = mtime;
407  reload(dyn.filename, file_desc, cmdline_desc);
408  SWC_LOGF(LOG_DEBUG, "dyn-cfg-file '%s' checked", dyn.filename.c_str());
409  }
410  }
411  } catch(...) {
413  }
414 }
415 
416 
417 }} // namespace SWC::Config
SWC::Config::Properties::reload
void reload(const std::string &fname, const Config::ParserConfig &filedesc, const Config::ParserConfig &cmddesc)
Definition: Properties.cc:50
SWC::Config::Parser
Definition: PropertiesParser.h:168
SWC::Core::logger
LogWriter logger
Definition: Logger.cc:15
SWC::Config::Parser::own_options
void own_options(Options &opts)
Definition: PropertiesParser.cc:577
SWC::Config::Properties::mutex
Core::MutexSptd mutex
Definition: Properties.h:26
SWC::Config::ParserConfig::add
ParserConfig & add(const ParserConfig &other_cfg)
Definition: PropertiesParser.cc:175
SWC_LOG_OSTREAM
#define SWC_LOG_OSTREAM
Definition: Logger.h:44
SWC::Config::Settings::m_cmd_args
Parser::Options m_cmd_args
Definition: Settings.h:66
SWC::Core::LogWriter::daemon
void daemon(const std::string &logs_path)
Definition: Logger.cc:80
SWC::Condition::str_cmp
int str_cmp(const char *s1, const char *s2) noexcept SWC_ATTRIBS((SWC_ATTRIB_O3))
Definition: Comparators_basic.h:217
SWC::Config::g_enum
Property::Value_enum_g::Ptr g_enum(const int32_t &v, Property::Value_enum_g::OnChg_t &&cb, Property::Value_enum_g::FromString_t &&from_string, Property::Value_enum_g::Repr_t &&repr)
Definition: PropertiesParser.cc:89
SWC::Config::Settings::init_process
void init_process(bool with_pid_file, const char *port_cfg=nullptr)
Definition: Settings.cc:340
SWC::Config::g_boo
Property::Value_bool_g::Ptr g_boo(const bool &v)
Definition: PropertiesParser.cc:65
SWC_LOGF
#define SWC_LOGF(priority, fmt,...)
Definition: Logger.h:188
SWC_LOG_OUT
#define SWC_LOG_OUT(pr, _code_)
Definition: Logger.h:178
USE_SWC_PATH_LOG
#define USE_SWC_PATH_LOG(_default_)
Definition: Settings.cc:23
SWC::Config::Settings::executable
std::string executable
Definition: Settings.h:36
SWC::Comm::Protocol::FsBroker::Handler::exists
void exists(const ConnHandlerPtr &conn, const Event::Ptr &ev)
Definition: Exists.h:17
SWC::Error::get_text
const char * get_text(const int err) noexcept
Definition: Error.cc:173
SWC::Config::init_app_options
void init_app_options(Settings *settings)
Definition: load_generator.cc:166
SWC::Config::Settings::m_dyn_files
Core::Vector< DynFile > m_dyn_files
Definition: Settings.h:93
SWC::LOG_INFO
@ LOG_INFO
Definition: Logger.h:35
SWC::Config::Properties::get_gbool
bool get_gbool(const char *name) const
Definition: Properties.h:97
USE_SWC_PATH_RUN
#define USE_SWC_PATH_RUN(_default_)
Definition: Settings.cc:29
SWC::Core::MutexSptd::scope
Definition: MutexSptd.h:96
SWC::Config::Properties::defaulted
bool defaulted(const char *name) const
Definition: Properties.cc:94
SWC::Config::Settings::cmdline_desc
ParserConfig cmdline_desc
Definition: Settings.h:32
SWC_PRINT
#define SWC_PRINT
Definition: Logger.h:167
SWC::Config::boo
Property::Value_bool::Ptr boo(const bool &v)
Definition: PropertiesParser.cc:21
SWC_PRINT_CLOSE
#define SWC_PRINT_CLOSE
Definition: Logger.h:171
SWC::Config::Properties::get_i16
uint16_t get_i16(const char *name) const
Definition: Properties.h:113
swcdb_copyrights
const char * swcdb_copyrights() noexcept
Definition: Version.cc:20
SWC::Config::Settings::parse_file
void parse_file(const std::string &fname, const char *onchg)
Definition: Settings.cc:177
SWC::Config::Parser::config
ParserConfig config
Definition: PropertiesParser.h:171
SWC::Core::LogWriter::initialize
void initialize(const std::string &name)
Definition: Logger.cc:74
Version.h
Settings.h
SWC::LOG_DEBUG
@ LOG_DEBUG
Definition: Logger.h:36
SWC_CURRENT_EXCEPTION
#define SWC_CURRENT_EXCEPTION(_msg_)
Definition: Exception.h:119
SWC::Config::Settings::usage_str
std::string usage_str(const char *usage=nullptr)
Definition: Settings.cc:371
SWC
The SWC-DB C++ namespace 'SWC'.
Definition: main.cc:12
SWC::Common::Files::Schema::remove
void remove(int &err, cid_t cid)
Definition: Schema.h:44
SWC::Config::Parser::parse_cmdline
void parse_cmdline(int argc, char *argv[])
Definition: PropertiesParser.cc:416
SWC::Config::Settings::file_desc
ParserConfig file_desc
Definition: Settings.h:33
USE_SWC_PATH_ETC
#define USE_SWC_PATH_ETC(_default_)
Definition: Settings.cc:17
SWC::Config::Properties::has
bool SWC_PURE_FUNC has(const char *name) const noexcept
Definition: Properties.cc:82
SWC::Config::strs
Property::Value_strings::Ptr strs(Strings &&v)
Definition: PropertiesParser.cc:49
SWC_THROWF
#define SWC_THROWF(_code_, _fmt_,...)
Definition: Exception.h:136
SWC::Config::ParserConfig::add_options
ParserConfig &SWC_CONST_FUNC add_options()
Definition: PropertiesParser.cc:223
SWC::Config::Settings::init_options
void init_options()
Definition: Settings.cc:103
SWC::Config::str
Property::Value_string::Ptr str(std::string &&v)
Definition: PropertiesParser.cc:45
SWC::Config::Properties::load
void load(const std::string &fname, const Config::ParserConfig &filedesc, const Config::ParserConfig &cmddesc, bool allow_unregistered=false, bool only_guarded=false)
Definition: Properties.cc:32
SWC::LOG_ERROR
@ LOG_ERROR
Definition: Logger.h:32
SWC::Config::Properties::load_from
void load_from(const Config::Parser::Options &opts, bool only_guarded=false)
Definition: Properties.cc:20
swcdb_version
const char * swcdb_version() noexcept
Definition: Version.cc:16
SWC::Core::LogWriter::from_string
static uint8_t SWC_PURE_FUNC from_string(const std::string &loglevel) noexcept
Definition: Logger.cc:44
SWC::format
std::string format(const char *fmt,...) __attribute__((format(printf
Definition: String.cc:17
SWC::Core::Vector< std::string >
SWC_QUICK_EXIT
#define SWC_QUICK_EXIT(_CODE_)
Definition: Compat.h:184
SWC::Config::Property::Value::zero_token
Ptr zero_token() noexcept
Definition: Property.cc:94
SWC::Config::Settings::init
void init(int argc, char *argv[], init_option_t app, init_option_t post_cmd_args)
Definition: Settings.cc:50
SWC::LOG_NOTICE
@ LOG_NOTICE
Definition: Logger.h:34
SWC::Config::Properties::get_str
std::string get_str(const char *name) const
Definition: Properties.h:77
SWC::Core::Vector::cend
constexpr SWC_CAN_INLINE const_iterator cend() const noexcept
Definition: Vector.h:232
SWC::Config::init_post_cmd_args
void init_post_cmd_args(Settings *settings)
Definition: Settings.h:64
SWC::LOG_WARN
@ LOG_WARN
Definition: Logger.h:33
SWC::Config::Settings::parse_args
void parse_args(int argc, char *argv[])
Definition: Settings.cc:143
SWC::Config::Settings::load_files_by
void load_files_by(const char *fileprop, bool allow_unregistered)
Definition: Settings.cc:196
SWC::Config::Settings::init_option_t
void init_option_t(Settings *)
Definition: Settings.h:30
SWC::Config::Settings::Settings
Settings()
Definition: Settings.cc:37
SWC::Error::print
void print(std::ostream &out, int err)
Definition: Error.cc:191
SWC::Core::Vector::cbegin
constexpr SWC_CAN_INLINE const_iterator cbegin() const noexcept
Definition: Vector.h:216
SWC::Core::to_string
SWC_CAN_INLINE std::string to_string(const BitFieldInt< T, SZ > &v)
Definition: BitFieldInt.h:263
SWC::Config::Properties::get_bool
bool get_bool(const char *name) const
Definition: Properties.h:89
SWC_LOG_CURRENT_EXCEPTION
#define SWC_LOG_CURRENT_EXCEPTION(_s_)
Definition: Exception.h:144
SWC::Error::Exception
Definition: Exception.h:21
SWC::Core::LogWriter::set_level
constexpr SWC_CAN_INLINE void set_level(uint8_t level) noexcept
Definition: Logger.h:85
SWC::Config::Settings::install_path
std::string install_path
Definition: Settings.h:35
SWC::Config::Settings::check_dynamic_files
void check_dynamic_files() noexcept
Definition: Settings.cc:400
SWC::Core::LogWriter::repr
static std::string repr(uint8_t priority)
Definition: Logger.cc:38
SWC::Config::Settings::~Settings
~Settings() noexcept
Definition: Settings.cc:47
SWC::Config::ParserConfig::definition
ParserConfig & definition(const char *u)
Definition: PropertiesParser.cc:163