Added config load from files(main/service).
[bpdyndnsd] / src / config.cpp
1 /** @file
2  * @brief Config class implementation. This class represents the actual configuration.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "config.h"
11
12 /**
13  * Default Constructor. Available command line arguments with their default values are defined here.
14  */
15 Config::Config()
16     : Daemon_mode(true)
17     , Loglevel(0)
18     , Syslog(true)
19 {
20     // Define valid command line parameters
21     Opt_desc_cmd = new po::options_description("Command line options");
22     Opt_desc_cmd->add_options()
23         ("help,?","Show help.")
24         ("version,v","Show version.")
25         ("protocol,q",po::value<string>(),"Set the service protocol type.")
26         ("host,h",po::value<string>(),"Set the hostname to update.")
27         ("login,l",po::value<string>(),"Set the login.")
28         ("password,p",po::value<string>(),"Set the password.")
29     ;
30
31     // Define valid config file main section parameters
32     Opt_desc_conf_main = new po::options_description("Config file main section options");
33     Opt_desc_conf_main->add_options()
34         ("main.daemon_mode",po::value<bool>()->default_value(false),"Run as system daemon.")
35         ("main.logfile",po::value<string>()->default_value("/var/log/bpdyndns.log"),"Where to log.")
36         ("main.loglevel",po::value<int>()->default_value(0),"Loglevel.")
37         ("main.syslog",po::value<bool>()->default_value(false),"Use syslog facility.")
38     ;
39
40     // Define valid config file main section parameters
41     Opt_desc_conf_service = new po::options_description("Config file service section options");
42     Opt_desc_conf_service->add_options()
43         ("service.protocol",po::value<string>(),"The service protocol.")
44         ("service.host",po::value<string>(),"The hostname to update.")
45         ("service.login",po::value<string>(),"Login name.")
46         ("service.password",po::value<string>(),"Corresponding password.")
47     ;
48 }
49
50
51 /**
52  * Default Destructor
53  */
54 Config::~Config()
55 {
56     delete Opt_desc_cmd;
57     delete Opt_desc_conf_main;
58     delete Opt_desc_conf_service;
59 }
60
61
62 /**
63  * Parses the command line arguments and does the needed actions.
64  * @param argc Command line argument number given to main.
65  * @param argv[] Pointer to command line argument array given to main.
66  * @return 0 if all is fine,
67  */
68 int Config::parse_cmd_line(int argc, char *argv[])
69 {
70     try
71     {
72         po::variables_map vm;
73         po::store(po::parse_command_line(argc, argv, *this->Opt_desc_cmd), vm);
74         po::notify(vm);
75
76         if(vm.count("help"))
77             return 1;
78         else if(vm.count("version"))
79             return 2;
80
81         // Are all needed options set to create a Service Object
82         if(vm.count("protocol") && vm.count("host") && vm.count("login") && vm.count("password"))
83         {
84             // Get the cmd parameter values for protocol host login and password
85             string protocol = vm["protocol"].as<string>();
86             string host = vm["host"].as<string>();
87             string login = vm["login"].as<string>();
88             string password = vm["password"].as<string>();
89
90             //TODO: convert protocol option to lowercase
91
92             Services.push_back(create_service(protocol,host,login,password));
93         }
94         else
95         {
96             cout << "Not all needed options set!\n" << endl;
97             return 1;
98         }
99     }
100     catch(po::unknown_option e)
101     {
102         cout << "Unknown option set." << endl;
103         return 1;
104     }
105     return 0;
106 }
107
108
109 /**
110  * 
111  * @param protocol 
112  * @param host 
113  * @param login 
114  * @param password 
115  * @return A pointer to the created Service object.
116  */
117 Service * Config::create_service(string protocol,string host, string login, string password)
118 {
119     Service * service;
120     if(protocol == "dhs")
121     {
122         service = new DHS(host,login,password);
123     }
124     else if(protocol == "ods")
125     {
126         service = new ODS(host,login,password);
127     }
128     return service;
129 }
130
131
132 /**
133  * Loads the main and the service config file and does the needed action.
134  * @param config_path The path to the config directory.
135  * @return 0 if all is fine.
136  */
137 int Config::load_config_from_files(string config_path)
138 {
139     fs::path full_config_path = fs::system_complete(fs::path(config_path));
140
141     if ( fs::exists(full_config_path) && fs::is_directory(full_config_path) )
142     {
143         fs::directory_iterator end_iter;
144         for ( fs::directory_iterator dir_itr(full_config_path) ; dir_itr != end_iter ; ++dir_itr )
145         {
146             if( fs::is_regular_file( dir_itr->status() ) )
147             {
148                 string actual_file = dir_itr->path().filename();
149                 boost::regex expr(".*\.conf?");
150                 // If it is the main config file do the following
151                 if ( actual_file == "bpdyndnsd.conf" )
152                 {
153                     string full_filename = dir_itr->path().string();
154                     cout << "Loading main config file: " << full_filename << endl;
155                     ifstream main_config_file(full_filename.c_str(),ifstream::in);
156                     if(main_config_file.is_open())
157                     {
158                         try
159                         {
160                             po::variables_map vm;
161                             po::parsed_options parsed_main_options = po::parse_config_file(main_config_file,*this->Opt_desc_conf_main,true);
162                             po::store(parsed_main_options,vm);
163                             po::notify(vm);
164
165                             if(vm.count("main.daemon_mode") && vm.count("main.logfile") && vm.count("main.loglevel") && vm.count("main.syslog"))
166                             {
167                                 Daemon_mode = vm["main.daemon_mode"].as<bool>();
168                                 Logfile = vm["main.logfile"].as<string>();
169                                 Loglevel = vm["main.loglevel"].as<int>();
170                                 Syslog = vm["main.syslog"].as<bool>();
171                             }
172                         }
173                         catch ( po::unknown_option e )
174                         {
175                             // unknown option in config file detected
176                             main_config_file.close();
177                             cout << "Unknown option in main config file detected!" << endl;
178                             return 3;
179                         }
180                         main_config_file.close();
181                     }
182                     else
183                     {
184                         cout << "Can't open main config file for reading: " << main_config_file << endl;
185                         return 4;
186                     }
187                 }
188                 // If it is a service definition file *.conf, parse it and generate the corresponding service
189                 else if ( boost::regex_search( actual_file,expr ) )
190                 {
191                     string full_filename = dir_itr->path().string();
192                     cout << "Loading service config file: " << full_filename << endl;
193                     ifstream service_config_file(full_filename.c_str(),ifstream::in);
194                     if(service_config_file.is_open())
195                     {
196                         try
197                         {
198                             po::variables_map vm;
199                             po::parsed_options parsed_service_options = po::parse_config_file(service_config_file,*this->Opt_desc_conf_service,true);
200                             po::store(parsed_service_options,vm);
201                             po::notify(vm);
202
203                             if(vm.count("service.protocol") && vm.count("service.host") && vm.count("service.login") && vm.count("service.password"))
204                             {
205                                 // create the corresponding service
206                                 Services.push_back(create_service(vm["service.protocol"].as<string>(),vm["service.host"].as<string>(),vm["service.login"].as<string>(),vm["service.password"].as<string>()));
207                             }
208                         }
209                         catch ( po::unknown_option e )
210                         {
211                             // unknown option in config file detected
212                             service_config_file.close();
213                             cout << "Unknown option in service config file detected!" << endl;
214                             return 3;
215                         }
216                         service_config_file.close();
217                     }
218                     else
219                     {
220                         cout << "Can't open service config file for reading: " << service_config_file << endl;
221                         return 4;
222                     }
223                 }
224             }
225         }
226     }
227     else
228     {
229         cout << "Path doesn't exist or is not a directory" << endl;
230         return 4;
231     }
232     return 0;
233 }
234
235
236 /**
237  * Getter method for Service list member.
238  * @return Pointer to a list of Service's.
239  */
240 list<Service*> Config::get_services()
241 {
242     return this->Services;
243 }
244
245
246 /**
247  * Prints out the usage to the command line.
248  */
249 void Config::print_usage()
250 {
251     cout << "Usage: bpdyndnsd [Command line options]" << "\n" << endl;
252     cout << *Opt_desc_cmd << endl;
253 }
254
255
256 /**
257  * Prints out the programm name and the given version string on stdout.
258  * @param version Version string.
259  */
260 void Config::print_version(string version)
261 {
262     cout << "Bullet proof dynamic dns daemon.\nbpdyndnsd " << version << endl;
263 }