blob: ca5118edf53e57d41433b625bc01eb004306e024 [file] [log] [blame]
/**
* @brief D-Bus signal watcher.
*
* This file is part of HostLogger project.
*
* Copyright (c) 2018 YADRO
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.hpp"
#include "dbus_watch.hpp"
#include <set>
#include <string>
#include <chrono>
// D-Bus path to the host state object
#define DBUS_HOST_OBJECT_PATH "/xyz/openbmc_project/state/host0"
// Macro to normalize SDBus status code:
// positive code is not an error in the systemd dbus implementation.
#define DBUS_RC_TO_ERR(c) (c = (c <= 0 ? -c : 0))
DbusWatcher::DbusWatcher(LogManager& logManager, sdbusplus::bus::bus& bus)
: logManager_(logManager),
bus_(bus)
{
}
int DbusWatcher::initialize()
{
int rc;
// Add IO callback for host's log stream socket
rc = sd_event_add_io(bus_.get_event(), NULL,
logManager_.getHostLogFd(),
EPOLLIN, &DbusWatcher::ioCallback, this);
if (DBUS_RC_TO_ERR(rc)) {
fprintf(stderr, "Unable to add IO handler: %i %s\n",
rc, strerror(rc));
return rc;
}
// Add flush handler
if (loggerConfig.flushPeriod == 0)
registerEventHandler();
else
rc = registerTimerHandler();
return rc;
}
void DbusWatcher::registerEventHandler()
{
conds_["xyz.openbmc_project.State.Host"] = {
.property = "RequestedHostTransition",
.values = {
"xyz.openbmc_project.State.Host.Transition.On"
}
};
conds_["xyz.openbmc_project.State.OperatingSystem.Status"] = {
.property = "OperatingSystemState",
.values = {
"xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.BootComplete",
"xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"
}
};
for (auto& cond: conds_) {
cond.second.match = std::make_unique<sdbusplus::bus::match_t>(bus_,
sdbusplus::bus::match::rules::propertiesChanged(
DBUS_HOST_OBJECT_PATH, cond.first),
[this](auto& msg){ this->hostStateHandler(msg); });
}
}
int DbusWatcher::registerTimerHandler()
{
int rc;
sd_event_source* ev = NULL;
rc = sd_event_add_time(bus_.get_event(), &ev, CLOCK_MONOTONIC,
UINT64_MAX, 0, &DbusWatcher::timerCallback, this);
if (DBUS_RC_TO_ERR(rc)) {
fprintf(stderr, "Unable to add timer handler: %i %s\n", rc, strerror(rc));
return rc;
}
rc = sd_event_source_set_enabled(ev, SD_EVENT_ON);
if (DBUS_RC_TO_ERR(rc)) {
fprintf(stderr, "Unable to enable timer handler: %i %s\n", rc, strerror(rc));
return rc;
}
return setupTimer(ev);
}
int DbusWatcher::setupTimer(sd_event_source* event)
{
// Get the current time and add the delta (flush period)
using namespace std::chrono;
auto now = steady_clock::now().time_since_epoch();
hours timeOut(loggerConfig.flushPeriod);
auto expireTime = duration_cast<microseconds>(now) +
duration_cast<microseconds>(timeOut);
//Set the time
int rc = sd_event_source_set_time(event, expireTime.count());
if (DBUS_RC_TO_ERR(rc))
fprintf(stderr, "Unable to set timer handler: %i %s\n", rc, strerror(rc));
return rc;
}
void DbusWatcher::hostStateHandler(sdbusplus::message::message& msg)
{
std::map<std::string, sdbusplus::message::variant<std::string>> properties;
std::string interface;
msg.read(interface, properties);
bool needFlush = false;
const auto itc = conds_.find(interface);
if (itc != conds_.end()) {
const auto itp = properties.find(itc->second.property);
if (itp != properties.end()) {
const auto& propVal = sdbusplus::message::variant_ns::get<std::string>(itp->second);
needFlush = itc->second.values.find(propVal) != itc->second.values.end();
}
}
if (needFlush)
logManager_.flush();
}
int DbusWatcher::ioCallback(sd_event_source* /*event*/, int /*fd*/, uint32_t /*revents*/, void* data)
{
DbusWatcher* instance = static_cast<DbusWatcher*>(data);
instance->logManager_.handleHostLog();
return 0;
}
int DbusWatcher::timerCallback(sd_event_source* event, uint64_t /*usec*/, void* data)
{
DbusWatcher* instance = static_cast<DbusWatcher*>(data);
instance->logManager_.flush();
return instance->setupTimer(event);
}