mavtables  0.2.1
MAVLink router and firewall.
Options.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
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 as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <iostream>
19 #include <stdexcept>
20 #include <string>
21 
22 #include <boost/program_options.hpp>
23 
24 #include "config.hpp"
25 #include "Options.hpp"
26 
27 
28 namespace po = boost::program_options;
29 
30 
31 /** Construct an options object.
32  *
33  * This will parse the command line arguments and construct an object for
34  * passing the result of these arguments to the application.
35  *
36  * The first two arguments are designed to be taken directly from the inputs to
37  * the standard `main` function.
38  *
39  * \param argc The number of command line arguments given.
40  * \param argv The command line arguments, as given in the arguments to the
41  * main function.
42  * \param filesystem A filesystem instance. The default is to construct an
43  * instance. This exists for testing purposes.
44  * \throws std::runtime_error if no configuration file can be found.
45  */
47  int argc, const char *argv[], const Filesystem &filesystem)
48  : continue_(true), loglevel_(0)
49 {
50  // Command line options.
51  po::options_description options(
52  "usage: " + std::string(argv[0]));
53  options.add_options()
54  ("help,h", "print this message")
55  ("config", po::value<std::string>(), "specify configuration file")
56  ("ast", "print AST of configuration file (do not run)")
57  ("version", "print version and license information")
58  ("loglevel", po::value<unsigned int>(),
59  "level of logging, between 0 and 3");
60  po::variables_map vm;
61  po::store(po::parse_command_line(argc, argv, options), vm);
62  po::notify(vm);
63 
64  // Print help.
65  if (vm.count("help"))
66  {
67  std::cout << options << std::endl;
68  continue_ = false;
69  return;
70  }
71 
72  // Print version information.
73  if (vm.count("version"))
74  {
75  std::cout << "mavtables (SHAMU Project) ";
76  std::cout << "v" << std::to_string(VERSION_MAJOR);
77  std::cout << "." << std::to_string(VERSION_MINOR);
78  std::cout << "." << std::to_string(VERSION_PATCH) << "\n";
79  std::cout << "Copyright (C) 2018 Michael R. Shannon\n";
80  std::cout << "\n";
81  std::cout << "License: GPL v2.0 or any later version.\n";
82  std::cout << "This is free software; see the source for copying "
83  "conditions. ";
84  std::cout << "There is NO\nwarranty; not even for MERCHANTABILITY or "
85  "FITNESS ";
86  std::cout << "FOR A PARTICULAR PURPOSE." << std::endl;
87  continue_ = false;
88  return;
89  }
90 
91  // Find configuration file.
92  if (vm.count("config"))
93  {
94  if (filesystem.exists(vm["config"].as<std::string>()))
95  {
96  config_file_ = vm["config"].as<std::string>();
97  }
98  else
99  {
100  continue_ = false;
101  throw std::runtime_error(
102  "mavtables could not locate a configuration file");
103  }
104  }
105  else
106  {
107  if (auto config_file = find_config(filesystem))
108  {
109  config_file_ = config_file.value();
110  }
111  else
112  {
113  continue_ = false;
114  throw std::runtime_error(
115  "mavtables could not locate a configuration file");
116  }
117  }
118 
119  if (vm.count("loglevel"))
120  {
121  loglevel_ = vm["loglevel"].as<unsigned int>();
122  }
123 
124  // Determine actions.
125  print_ast_ = vm.count("ast");
126  run_firewall_ = !print_ast_;
127 }
128 
129 
130 /** Determine whether to print the configuration file's AST or not.
131  *
132  * \retval true Print abstract syntax tree of configuration file.
133  * \retval false Don't print abstract syntax tree of configuration file.
134  */
136 {
137  return print_ast_;
138 }
139 
140 
141 /** Get path to an existing configuration file.
142  *
143  * \returns The path to an existing, but not necessarily valid configuration
144  * file.
145  */
146 std::string Options::config_file()
147 {
148  return config_file_;
149 }
150 
151 
152 /** Get the log level.
153  *
154  * \returns The level to log at, between 0 and 3.
155  */
156 unsigned int Options::loglevel()
157 {
158  return loglevel_;
159 }
160 
161 
162 /** Determine whether to run the firewall/router or not.
163  *
164  * \retval true Run the firewall/router.
165  * \retval false Don't run the firewall/router.
166  */
168 {
169  return run_firewall_;
170 }
171 
172 
173 /** Determine if the \ref Options object is valid.
174  *
175  * \retval true %If the options object successfully parsed the command line
176  * arguments.
177  * \retval false %If the program should exit immediately.
178  */
179 Options::operator bool() const
180 {
181  return continue_;
182 }
183 
184 
185 /** Find the configuration file.
186  *
187  * Find the first configuration file in the list below:
188  * 1. The target of the `MAVTABLES_CONFIG_PATH` environment variable.
189  * 2. `.mavtablesrc` in the current directory.
190  * 3. `.mavtablesrc` at `$HOME/.mavtablesrc`.
191  * 4. The main configuration file at `PREFIX/etc/mavtables.conf`.
192  *
193  * \relates Options
194  * \param filesystem A filesystem instance. The default is to construct an
195  * instance. This exists for testing purposes.
196  * \returns The path to the first configuration file found. {} if no
197  * configuration file could be found.
198  */
199 std::optional<std::string> find_config(const Filesystem &filesystem)
200 {
201  // Check MATABLES_CONFIG_PATH.
202  if (auto config_path = std::getenv("MAVTABLES_CONFIG_PATH"))
203  {
204  if (filesystem.exists(Filesystem::path(config_path)))
205  {
206  return config_path;
207  }
208  }
209 
210  // Check for .mavtablesrc in current directory.
211  if (filesystem.exists(".mavtablesrc"))
212  {
213  return ".mavtablesrc";
214  }
215 
216  // Check for .mavtablesrc in home directory.
217  if (auto home = std::getenv("HOME"))
218  {
219  Filesystem::path config_path(home);
220  config_path /= ".mavtablesrc";
221 
222  if (filesystem.exists(config_path))
223  {
224  return config_path.string();
225  }
226  }
227 
228  // Check for PREFIX/etc/mavtables.conf.
229  if (filesystem.exists(PREFIX "/etc/mavtables.conf"))
230  {
231  return PREFIX "/etc/mavtables.conf";
232  }
233 
234  return {};
235 }
bool run()
Definition: Options.cpp:167
bool ast()
Definition: Options.cpp:135
unsigned int loglevel()
Definition: Options.cpp:156
std::optional< std::string > find_config(const Filesystem &filesystem)
Definition: Options.cpp:199
TEST_VIRTUAL bool exists(const path &p) const
Definition: Filesystem.cpp:36
boost::filesystem::path path
Definition: Filesystem.hpp:40
Options(int argc, const char *argv[], const Filesystem &filesystem=Filesystem())
Definition: Options.cpp:46
std::string config_file()
Definition: Options.cpp:146