blob: 43ba4ab62e019b90b5facb2925dc2acc899864ad [file] [log] [blame]
// Copyright 2014 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 <string>
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/file_util.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/message_loop/message_loop.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <dbus/bus.h>
#include <sysexits.h>
#include "buffet/async_event_sequencer.h"
#include "buffet/dbus_constants.h"
#include "buffet/exported_object_manager.h"
#include "buffet/manager.h"
using buffet::dbus_utils::AsyncEventSequencer;
using buffet::dbus_utils::ExportedObjectManager;
namespace {
static const char kLogRoot[] = "logroot";
static const char kHelp[] = "help";
static const char kDefaultLogRoot[] = "/var/log";
// The help message shown if help flag is passed to the program.
static const char kHelpMessage[] = "\n"
"Available Switches: \n"
" --logroot=/path/to/logroot\n"
" Specifies parent directory to put buffet logs in.\n";
// Returns |utime| as a string
std::string GetTimeAsString(time_t utime) {
struct tm tm;
CHECK_EQ(localtime_r(&utime, &tm), &tm);
char str[16];
CHECK_EQ(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm), 15UL);
return std::string(str);
}
// Sets up a symlink to point to log file.
void SetupLogSymlink(const std::string& symlink_path,
const std::string& log_path) {
base::DeleteFile(base::FilePath(symlink_path), true);
if (symlink(log_path.c_str(), symlink_path.c_str()) == -1) {
LOG(ERROR) << "Unable to create symlink " << symlink_path
<< " pointing at " << log_path;
}
}
// Creates new log file based on timestamp in |log_root|/buffet.
std::string SetupLogFile(const std::string& log_root) {
const auto log_symlink = log_root + "/buffet.log";
const auto logs_dir = log_root + "/buffet";
const auto log_path =
base::StringPrintf("%s/buffet.%s",
logs_dir.c_str(),
GetTimeAsString(::time(NULL)).c_str());
mkdir(logs_dir.c_str(), 0755);
SetupLogSymlink(log_symlink, log_path);
return log_symlink;
}
// Sets up logging for buffet.
void SetupLogging(const std::string& log_root) {
const auto log_file = SetupLogFile(log_root);
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = log_file.c_str();
settings.lock_log = logging::DONT_LOCK_LOG_FILE;
settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
logging::InitLogging(settings);
}
void TakeServiceOwnership(scoped_refptr<dbus::Bus> bus, bool success) {
// Success should always be true since we've said that failures are
// fatal.
CHECK(success) << "Init of one or more objects has failed.";
CHECK(bus->RequestOwnershipAndBlock(buffet::dbus_constants::kServiceName,
dbus::Bus::REQUIRE_PRIMARY))
<< "Unable to take ownership of " << buffet::dbus_constants::kServiceName;
}
void EnterMainLoop(base::MessageLoopForIO* message_loop,
scoped_refptr<dbus::Bus> bus) {
scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
ExportedObjectManager object_manager(
bus, dbus::ObjectPath(buffet::dbus_constants::kRootServicePath));
buffet::Manager manager(bus, object_manager.AsWeakPtr());
object_manager.Init(
sequencer->GetHandler("ObjectManager.Init() failed.", true));
manager.Init(sequencer->GetHandler("Manager.Init() failed.", true));
sequencer->OnAllTasksCompletedCall(
{base::Bind(&TakeServiceOwnership, bus)});
// Release our handle on the sequencer so that it gets deleted after
// both callbacks return.
sequencer = nullptr;
LOG(INFO) << "Entering mainloop.";
message_loop->Run();
}
} // namespace
int main(int argc, char* argv[]) {
// Parse the args and check for extra args.
CommandLine::Init(argc, argv);
CommandLine* cl = CommandLine::ForCurrentProcess();
if (cl->HasSwitch(kHelp)) {
LOG(INFO) << kHelpMessage;
return EX_USAGE;
}
std::string log_root = std::string(kDefaultLogRoot);
if (cl->HasSwitch(kLogRoot)) {
log_root = cl->GetSwitchValueASCII(kLogRoot);
}
SetupLogging(log_root);
base::AtExitManager at_exit_manager;
base::MessageLoopForIO message_loop;
dbus::Bus::Options options;
// TODO(sosa): Should this be on the system bus?
options.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
CHECK(bus->Connect());
// Our top level objects expect the bus to exist in a connected state for
// the duration of their lifetimes.
EnterMainLoop(&message_loop, bus);
bus->ShutdownAndBlock();
return EX_OK;
}