blob: 30c8656e5693a1776c6097991e40efd871324a02 [file] [log] [blame]
Richard Marian Thomaiyar7a362772019-06-16 19:11:35 +05301/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "u-boot-env-mgr.hpp"
18#include <phosphor-logging/log.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <boost/process/child.hpp>
21#include <boost/process/io.hpp>
22#include <vector>
23#include <unordered_map>
24#include <xyz/openbmc_project/Common/error.hpp>
25
26template <typename... ArgTypes>
27static std::vector<std::string> executeCmd(const char* path,
28 ArgTypes&&... tArgs)
29{
30 std::vector<std::string> stdOutput;
31 boost::process::ipstream stdOutStream;
32 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
33 boost::process::std_out > stdOutStream);
34 std::string stdOutLine;
35
36 while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
37 !stdOutLine.empty())
38 {
39 stdOutput.emplace_back(stdOutLine);
40 }
41
42 execProg.wait();
43
44 int retCode = execProg.exit_code();
45 if (retCode)
46 {
47 phosphor::logging::log<phosphor::logging::level::ERR>(
48 "Command execution failed",
49 phosphor::logging::entry("PATH=%d", path),
50 phosphor::logging::entry("RETURN_CODE:%d", retCode));
51 phosphor::logging::elog<
52 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
53 }
54
55 return stdOutput;
56}
57
58UBootEnvMgr::UBootEnvMgr(boost::asio::io_service& io_,
59 sdbusplus::asio::object_server& srv_,
60 std::shared_ptr<sdbusplus::asio::connection>& conn_) :
61 io(io_),
62 server(srv_), conn(conn_)
63{
64 iface = server.add_interface(uBootEnvMgrPath, uBootEnvMgrIface);
65 iface->register_method("ReadAll", [this]() { return readAllVariable(); });
66 iface->register_method("Read", [this](const std::string& key) {
67 std::unordered_map<std::string, std::string> env = readAllVariable();
68 auto it = env.find(key);
69 if (it != env.end())
70 {
71 return it->second;
72 }
73 return std::string{};
74 });
75
76 iface->register_method(
77 "Write", [this](const std::string& key, const std::string& value) {
78 writeVariable(key, value);
79 });
80 iface->initialize(true);
81}
82
83std::unordered_map<std::string, std::string> UBootEnvMgr::readAllVariable()
84{
85 std::unordered_map<std::string, std::string> env;
86 std::vector<std::string> output = executeCmd("/sbin/fw_printenv");
87 for (const auto& entry : output)
88 {
89 size_t pos = entry.find("=");
90 if (pos + 1 >= entry.size())
91 {
92 phosphor::logging::log<phosphor::logging::level::ERR>(
93 "Invalid U-Boot environment",
94 phosphor::logging::entry("ENTRY=%s", entry.c_str()));
95 continue;
96 }
97 // using string instead of string_view for null termination
98 std::string key = entry.substr(0, pos);
99 std::string value = entry.substr(pos + 1);
100 env.emplace(key, value);
101 }
102 return env;
103}
104
105void UBootEnvMgr::writeVariable(const std::string& key,
106 const std::string& value)
107{
108 executeCmd("/sbin/fw_setenv", key.c_str(), value.c_str());
109 return;
110}