blob: 3295e596c6e52dd89ad138a8599cf4bcfa4f8b6c [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <signal.h>
#include <stdio.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include <unistd.h>
#include <base/command_line.h>
#include <base/logging.h>
#include <brillo/syslog_logging.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus-c++/glib-integration.h>
#include <dbus-c++/util.h>
#include "cromo/carrier.h"
#include "cromo/cromo_server.h"
#include "cromo/plugin_manager.h"
#include "cromo/sandbox.h"
#include "cromo/syslog_helper.h"
#ifndef VCSID
#define VCSID "<not set>"
#endif
DBus::Glib::BusDispatcher dispatcher;
GMainLoop* main_loop;
static CromoServer* server;
static const int kExitMaxTries = 10;
static int kExitTries = 0;
namespace switches {
// Comma-separated list of plugins to load at startup
static const char kPlugins[] = "plugins";
// Flag that causes shill to show the help message and exit.
static const char kHelp[] = "help";
// The help message shown if help flag is passed to the program.
static const char kHelpMessage[] = "\n"
"Available Switches: \n"
" --plugins\n"
" comma-separated list of plugins to load at startup\n";
} // namespace switches
// This function is run on a timer by exit_main_loop(). It calls all of the
// exit-ok hooks to see if they are all ready for the program to exit; it also
// keeps track of tries so that we time out appropriately if one of the devices
// isn't disconnecting properly.
static gboolean test_for_exit(void* arg) {
int* tries = static_cast<int*>(arg);
if ((*tries)++ < kExitMaxTries && !server->exit_ok_hooks().Run())
// Event needs to be scheduled again.
return TRUE;
g_main_loop_quit(main_loop);
// We're done here; exit the program.
return FALSE;
}
// This function starts exiting the main loop. We run all the pre-exit hooks,
// then keep testing every second to see if all the exit hooks think it's okay
// to exit.
static void exit_main_loop(void) {
server->start_exit_hooks().Run();
if (server->exit_ok_hooks().Run()) {
g_main_loop_quit(main_loop);
return;
}
g_timeout_add_seconds(1, test_for_exit, &kExitTries);
}
static gboolean do_signal(void* arg) {
intptr_t sig = reinterpret_cast<intptr_t>(arg);
LOG(INFO) << "Signal: " << sig;
if (sig == SIGTERM || sig == SIGINT) {
exit_main_loop();
}
return FALSE;
}
static void* handle_signals(void* arg) {
sigset_t sigs;
siginfo_t info;
info.si_signo = 0;
sigemptyset(&sigs);
sigaddset(&sigs, SIGTERM);
sigaddset(&sigs, SIGINT);
LOG(INFO) << "waiting for signals";
while (info.si_signo != SIGTERM && info.si_signo != SIGINT) {
sigwaitinfo(&sigs, &info);
g_idle_add(do_signal, reinterpret_cast<void*>(info.si_signo));
}
return nullptr;
}
static gboolean setup_signals(void* arg) {
pthread_t thr;
pthread_create(&thr, nullptr, handle_signals, nullptr);
return FALSE;
}
static void block_signals(void) {
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGTERM);
sigaddset(&sigs, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigs, nullptr);
}
// Always logs to the syslog and stderr.
void SetupLogging(void) {
int log_flags = 0;
log_flags |= brillo::kLogToSyslog;
log_flags |= brillo::kLogToStderr;
log_flags |= brillo::kLogHeader;
brillo::InitLog(log_flags);
}
int main(int argc, char* argv[]) {
// Drop privs right away for now.
// TODO(ellyjones): once we do more serious sandboxing, this will need to be
// broken into two parts, one to be done pre-plugin load and one to be done
// post-plugin load -- or we can just do the whole thing post-plugin load.
Sandbox::Enter();
base::CommandLine::Init(argc, argv);
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
if (cl->HasSwitch(switches::kHelp)) {
LOG(INFO) << switches::kHelpMessage;
return 0;
}
SysLogHelperInit();
SetupLogging();
block_signals();
DBus::default_dispatcher = &dispatcher;
dispatcher.attach(nullptr);
DBus::Connection conn = DBus::Connection::SystemBus();
CHECK(conn.acquire_name(CromoServer::kServiceName))
<< "Failed to acquire D-Bus name " << CromoServer::kServiceName;
server = new CromoServer(conn);
// Add carriers before plugins so that they can be overidden
AddBaselineCarriers(server);
// Instantiate modem handlers for each type of hardware supported
std::string plugins = cl->GetSwitchValueASCII(switches::kPlugins);
PluginManager::LoadPlugins(server, plugins);
dispatcher.enter();
main_loop = g_main_loop_new(nullptr, false);
g_idle_add(setup_signals, nullptr);
g_main_loop_run(main_loop);
PluginManager::UnloadPlugins(false);
LOG(INFO) << "Exit";
return 0;
}