24 #include <baseapp/run.h> 25 #include <baseapp/daemonize.h> 26 #include <baseapp/main_thread.h> 27 #include <baseapp/thread_manager.h> 29 #include <core/threading/thread.h> 31 #include <blackboard/local.h> 32 #include <config/sqlite.h> 33 #include <config/yaml.h> 34 #include <config/net_handler.h> 35 #include <utils/ipc/shm.h> 36 #include <utils/system/argparser.h> 37 #include <logging/multi.h> 38 #include <logging/console.h> 39 #include <logging/liblogger.h> 40 #include <logging/factory.h> 41 #include <logging/network.h> 42 #ifdef HAVE_LOGGING_FD_REDIRECT 43 # include <logging/fd_redirect.h> 45 #include <utils/time/clock.h> 46 #include <utils/time/time.h> 47 #include <netcomm/fawkes/network_manager.h> 48 #include <plugin/manager.h> 49 #include <plugin/net/handler.h> 50 #include <aspect/manager.h> 52 # include <tf/transform_listener.h> 53 # include <tf/transformer.h> 56 #include <sys/types.h> 74 ArgumentParser * argument_parser = NULL;
75 FawkesMainThread * main_thread = NULL;
76 MultiLogger * logger = NULL;
77 NetworkLogger * network_logger = NULL;
78 BlackBoard * blackboard = NULL;
79 Configuration * config = NULL;
80 PluginManager * plugin_manager = NULL;
81 AspectManager * aspect_manager = NULL;
82 ThreadManager * thread_manager = NULL;
83 FawkesNetworkManager * network_manager = NULL;
84 ConfigNetworkHandler * nethandler_config = NULL;
85 PluginNetworkHandler * nethandler_plugin = NULL;
87 SharedMemoryRegistry * shm_registry;
88 InitOptions * init_options = NULL;
89 tf::Transformer * tf_transformer = NULL;
90 tf::TransformListener * tf_listener = NULL;
91 Time * start_time = NULL;
92 #ifdef HAVE_LOGGING_FD_REDIRECT 93 LogFileDescriptorToLog * log_fd_redirect_stderr_ = NULL;
94 LogFileDescriptorToLog * log_fd_redirect_stdout_ = NULL;
98 FawkesMainThread::Runner * runner = NULL;
101 init(
int argc,
char **argv,
int & retval)
103 return init(InitOptions(argc, argv), retval);
108 init(InitOptions options,
int & retval)
110 init_options =
new InitOptions(options);
112 if (init_options->
show_help())
return true;
114 if ( options.daemonize() ) {
115 fawkes::daemon::init(options.daemon_pid_file(), options.basename());
116 if (options.daemonize_kill()) {
117 fawkes::daemon::kill();
120 }
else if (options.daemonize_status()) {
121 retval = fawkes::daemon::running() ? 0 : 1;
124 if (fawkes::daemon::start()) {
132 const char *user = NULL;
133 const char *group = NULL;
134 if (options.has_username()) {
135 user = options.username();
137 if (options.has_groupname()) {
138 group = options.groupname();
143 if (! (pw = getpwnam(user))) {
144 printf(
"Failed to find user %s, check -u argument.\n", user);
149 r = setreuid(pw->pw_uid, pw->pw_uid);
151 perror(
"Failed to drop privileges (user)");
157 if (! (gr = getgrnam(group))) {
158 printf(
"Failed to find group %s, check -g argument.\n", user);
163 r = setregid(gr->gr_gid, gr->gr_gid);
165 perror(
"Failed to drop privileges (group)");
173 struct passwd *uid_pw = getpwuid(getuid());
174 if (uid_pw == NULL) {
175 shm_registry =
new SharedMemoryRegistry();
178 if (asprintf(®istry_name, USER_SHM_NAME, uid_pw->pw_name) == -1) {
179 shm_registry =
new SharedMemoryRegistry();
181 shm_registry =
new SharedMemoryRegistry(registry_name);
186 if (! shm_registry) {
187 throw Exception(
"Failed to create shared memory registry");
191 if (options.has_loggers()) {
194 }
catch (Exception &e) {
195 e.append(
"Initializing multi logger failed");
199 logger =
new MultiLogger(
new ConsoleLogger());
206 const char *homedir = getenv(
"HOME");
209 if (asprintf(&userdir,
"%s/%s", homedir, USERDIR) != -1) {
210 if (access(userdir, W_OK) != 0) {
211 if (mkdir(userdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
212 logger->
log_warn(
"FawkesMainThread",
"Failed to create .fawkes " 213 "directory %s, trying without", userdir);
222 SQLiteConfiguration *sqconfig = NULL;
224 if (options.config_file() &&
225 fnmatch(
"*.sql", options.config_file(), FNM_PATHNAME) == 0)
227 sqconfig =
new SQLiteConfiguration(CONFDIR);
230 config =
new YamlConfiguration(CONFDIR);
233 config->
load(options.config_file());
237 SQLiteConfiguration::SQLiteValueIterator *i = sqconfig->modified_iterator();
239 std::string modtype = i->get_modtype();
240 if (modtype ==
"changed") {
241 logger->
log_warn(
"FawkesMainThread",
"Default config value CHANGED: %s" 242 "(was: %s now: %s)", i->path(),
243 i->get_oldvalue().c_str(), i->get_as_string().c_str());
244 }
else if (modtype ==
"erased") {
245 logger->
log_warn(
"FawkesMainThread",
"Default config value ERASED: %s",
248 logger->
log_debug(
"FawkesMainThread",
"Default config value ADDED: %s " 249 "(value: %s)", i->path(), i->get_as_string().c_str());
253 }
catch (Exception &e) {
254 logger->
log_warn(
"FawkesMainThread",
"Failed to read modified default " 255 "config values, no dump?");
259 if (! options.has_loggers()) {
261 if (config->
exists(
"/fawkes/mainapp/loggers")) {
263 std::string loggers = config->
get_string(
"/fawkes/mainapp/loggers");
264 MultiLogger *new_logger =
269 }
catch (Exception &e) {
270 logger->
log_warn(
"FawkesMainThread",
"Loggers set in config file, " 271 "but failed to read, exception follows.");
272 logger->
log_warn(
"FawkesMainThread", e);
277 if (config->
exists(
"/fawkes/mainapp/log_stderr_as_warn")) {
279 bool log_stderr_as_warn = config->
get_bool(
"/fawkes/mainapp/log_stderr_as_warn");
280 if (log_stderr_as_warn) {
281 #ifdef HAVE_LOGGING_FD_REDIRECT 282 log_fd_redirect_stderr_ =
283 new LogFileDescriptorToLog(STDERR_FILENO, logger,
"stderr",
Logger::LL_WARN);
285 logger->
log_warn(
"FawkesMainThread",
"stderr log redirection enabled but not available at compile time");
288 }
catch (Exception &e) {}
292 bool enable_ipv4 =
true;
293 bool enable_ipv6 =
true;
294 std::string listen_ipv4;
295 std::string listen_ipv6;
296 unsigned int net_tcp_port = 1910;
297 std::string net_service_name =
"Fawkes on %h";
298 if (options.has_net_tcp_port()) {
299 net_tcp_port = options.net_tcp_port();
302 net_tcp_port = config->
get_uint(
"/network/fawkes/tcp_port");
303 }
catch (Exception &e) {}
306 if (options.has_net_service_name()) {
307 net_service_name = options.net_service_name();
310 net_service_name = config->
get_string(
"/network/fawkes/service_name");
311 }
catch (Exception &e) {}
314 if (net_tcp_port > 65535) {
315 logger->
log_warn(
"FawkesMainThread",
"Invalid port '%u', using 1910",
321 enable_ipv4 = config->
get_bool(
"/network/ipv4/enable");
322 }
catch (Exception &e) {}
324 enable_ipv6 = config->
get_bool(
"/network/ipv6/enable");
325 }
catch (Exception &e) {}
328 listen_ipv4 = config->
get_string(
"/network/ipv4/listen");
329 }
catch (Exception &e) {}
331 listen_ipv6 = config->
get_string(
"/network/ipv6/listen");
332 }
catch (Exception &e) {}
335 logger->
log_warn(
"FawkesMainThread",
"Disabling IPv4 support");
338 logger->
log_warn(
"FawkesMainThread",
"Disabling IPv6 support");
340 if (! listen_ipv4.empty()) {
341 logger->
log_info(
"FawkesMainThread",
"Listening on IPv4 address %s", listen_ipv4.c_str());
343 if (! listen_ipv6.empty()) {
344 logger->
log_info(
"FawkesMainThread",
"Listening on IPv6 address %s", listen_ipv4.c_str());
348 std::string bb_magic_token =
"";
349 unsigned int bb_size = 2097152;
351 bb_magic_token = config->
get_string(
"/fawkes/mainapp/blackboard_magic_token");
352 logger->
log_info(
"FawkesMainApp",
"BlackBoard magic token defined. " 353 "Using shared memory BlackBoard.");
354 }
catch (Exception &e) {
358 bb_size = config->
get_uint(
"/fawkes/mainapp/blackboard_size");
359 }
catch (Exception &e) {
360 logger->
log_warn(
"FawkesMainApp",
"BlackBoard size not defined. " 361 "Will use %u, saving to default DB", bb_size);
366 if ( options.bb_cleanup()) {
372 LocalBlackBoard *lbb = NULL;
373 if ( bb_magic_token ==
"") {
374 lbb =
new LocalBlackBoard(bb_size);
376 lbb =
new LocalBlackBoard(bb_size, bb_magic_token.c_str());
381 tf_transformer =
new tf::Transformer();
382 tf_listener =
new tf::TransformListener(blackboard, tf_transformer);
385 aspect_manager =
new AspectManager();
386 thread_manager =
new ThreadManager(aspect_manager, aspect_manager);
388 plugin_manager =
new PluginManager(thread_manager, config,
389 "/fawkes/meta_plugins/",
390 options.plugin_module_flags(),
391 options.init_plugin_cache());
392 network_manager =
new FawkesNetworkManager(thread_manager,
393 enable_ipv4, enable_ipv6,
394 listen_ipv4, listen_ipv6,
396 net_service_name.c_str());
397 nethandler_config =
new ConfigNetworkHandler(config,
398 network_manager->hub());
400 nethandler_plugin =
new PluginNetworkHandler(plugin_manager,
401 network_manager->hub());
402 nethandler_plugin->
start();
404 network_logger =
new NetworkLogger(network_manager->hub(),
409 start_time =
new Time(clock);
411 lbb->start_nethandler(network_manager->hub());
418 options.load_plugin_list(),
419 options.default_plugin());
423 config, logger, clock,
424 network_manager->hub(),
427 network_manager->nnresolver(),
428 network_manager->service_publisher(),
429 network_manager->service_browser(),
430 plugin_manager, tf_transformer);
440 fawkes::daemon::cleanup();
443 if (nethandler_plugin) {
444 nethandler_plugin->cancel();
445 nethandler_plugin->join();
451 logger->remove_logger(network_logger);
452 delete network_logger;
455 delete nethandler_config;
456 delete nethandler_plugin;
457 delete plugin_manager;
461 delete tf_transformer;
465 delete argument_parser;
467 delete network_manager;
468 delete thread_manager;
469 delete aspect_manager;
471 #ifdef HAVE_LOGGING_FD_REDIRECT 472 delete log_fd_redirect_stderr_;
473 delete log_fd_redirect_stdout_;
477 argument_parser = NULL;
479 nethandler_config = NULL;
480 nethandler_plugin = NULL;
481 plugin_manager = NULL;
482 network_manager = NULL;
484 thread_manager = NULL;
485 aspect_manager = NULL;
488 #ifdef HAVE_LOGGING_FD_REDIRECT 489 log_fd_redirect_stderr_ = NULL;
490 log_fd_redirect_stdout_ = NULL;
504 }
catch (Exception &e) {}
516 print_usage(init_options->
basename());
521 runner =
new FawkesMainThread::Runner(main_thread, defsigs);
525 }
catch (Exception &e) {
526 printf(
"Running Fawkes failed\n");
543 kill(getpid(), SIGINT);
547 print_usage(
const char *progname)
549 printf(
"Fawkes Main Application - Usage Instructions\n" 550 "================================================" 551 "===============================\n" 552 "Usage: %s [options] [plugins]\n" 554 " [plugins] is a space-separated list of plugins to load on startup in given order\n" 555 " [options] is one or more of:\n" 556 " -h These help instructions\n" 557 " -C Cleanup old BB and shared memory segments\n" 558 " -c config file Configuration file to load.\n" 559 " Examples: default.sql or config.yaml\n" 560 " -d Enable debug output\n" 561 " -q[qqq] Quiet mode, -q omits debug, -qq debug and" 563 "-qqq omit debug, info and warn, -qqqq no output\n" 564 " -l level Set log level directly mutually exclusive" 566 "level is one of debug, info, warn, error, or none\n" 567 " -L loggers Define loggers. By default this setting is" 569 "config (console logger if unset). Format is:\n" 570 " logger:args[;logger2:args2[!...]]\n" 571 " Currently supported:\n" 572 " console, file:file.log, network logger always added\n" 573 " -p plugins List of plugins to load on startup in given order\n" 574 " -P port TCP port to listen on for Fawkes network connections.\n" 575 " --net-service-name=name mDNS service name to use.\n" 576 " -u user Drop privileges and run as given user.\n" 577 " -g group Drop privileges and run as given group.\n" 578 #ifdef HAVE_LIBDAEMON
579 " -D[pid file] Run daemonized in the background, pid file " 581 "default is /var/run/fawkes.pid, must be absolute path.\n" 582 " -D[pid file] -k Kill a daemonized Fawkes running in the" 584 " -D[pid file] -s Check status of daemon.\n" 600 return now - start_time;
static void finalize()
Delete internal logger.
virtual void load(const char *file_path)=0
Load configuration.
static Clock * instance()
Clock initializer.
static void cleanup(const char *magic_token, bool use_lister=false)
Cleanup orphaned BlackBoard segments.
Fawkes library namespace.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
warning, should be investigated but software still functions, an example is that something was reques...
A class for handling time.
static void init_main()
Initialize Thread wrapper instance for main thread.
static MultiLogger * multilogger_instance(const char *as, Logger::LogLevel default_ll=Logger::LL_DEBUG)
Create MultiLogger instance.
InitOptions & default_signal_handlers(bool enable)
Set default signal handlers.
virtual void set_loglevel(LogLevel level)
Sets the log level.
void register_default_inifins(BlackBoard *blackboard, ThreadCollector *collector, Configuration *config, Logger *logger, Clock *clock, FawkesNetworkHub *fnethub, MainLoopEmployer *mloop_employer, LoggerEmployer *logger_employer, BlockedTimingExecutor *btexec, NetworkNameResolver *nnresolver, ServicePublisher *service_publisher, ServiceBrowser *service_browser, PluginManager *pmanager, tf::Transformer *tf_listener)
Register default aspect initializer/finalizer.
virtual void set_default_uint(const char *path, unsigned int uint)=0
Set new default value in configuration of type unsigned int.
static void destroy_main()
Destroy main thread wrapper instance.
virtual void log_warn(const char *component, const char *format,...)
Log warning message.
InitOptions & show_help(bool show_help)
Set to show help.
void add_logger(Logger *logger)
Add a logger.
static void finalize()
Finalize.
virtual void log_info(const char *component, const char *format,...)
Log informational message.
static void init(MultiLogger *multi_logger=NULL)
Initialize logger.
void run()
Run main thread.
virtual bool exists(const char *path)=0
Check if a given value exists.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
const char * basename() const
Get program basename.
virtual LogLevel loglevel()
Get log level.
Fawkes default main thread.
ThreadCollector * aspect_collector() const
Get a thread collector to be used for an aspect initializer.
virtual void log_debug(const char *component, const char *format,...)
Log debug message.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
void start(bool wait=true)
Call this method to start the thread.
InitOptions & daemonize(bool daemonize, bool kill=false, bool status=false, const char *pid_file=0)
Set daemonization options.
static void cleanup(const char *name=0)
Cleanup existing shared memory segments.