blob: 3d51639584865d3ca443177fd9a282efbd9d992d [file] [log] [blame] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* 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 "cmd_helper.hpp"
#include "nsm_config_cmd.hpp"
#include "nsm_diag_cmd.hpp"
#include "nsm_discovery_cmd.hpp"
#include "nsm_firmware_cmd.hpp"
#include "nsm_passthrough_cmd.hpp"
#include "nsm_telemetry_cmd.hpp"
#include <dbus/dbus.h>
#include <CLI/CLI.hpp>
namespace nsmtool
{
namespace raw
{
using namespace nsmtool::helper;
namespace
{
std::vector<std::unique_ptr<CommandInterface>> commands;
}
class RawOp : public CommandInterface
{
public:
~RawOp() = default;
RawOp() = delete;
RawOp(const RawOp&) = delete;
RawOp(RawOp&&) = default;
RawOp& operator=(const RawOp&) = delete;
RawOp& operator=(RawOp&&) = default;
explicit RawOp(const char* type, const char* name, CLI::App* app) :
CommandInterface(type, name, app)
{
app->add_option("-d,--data", rawData, "raw data")
->required()
->expected(-3);
}
std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
return {NSM_SUCCESS, rawData};
}
void parseResponseMsg(nsm_msg* /* responsePtr */,
size_t /* payloadLength */) override
{}
private:
std::vector<uint8_t> rawData;
};
void registerCommand(CLI::App& app)
{
auto raw = app.add_subcommand("raw",
"send a raw request and print response");
commands.push_back(std::make_unique<RawOp>("raw", "raw", raw));
}
} // namespace raw
} // namespace nsmtool
bool isNsmdServiceActive()
{
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr);
if (!conn)
return false;
DBusMessage* msg = dbus_message_new_method_call(
"org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
"NameHasOwner");
if (!msg)
{
dbus_connection_unref(conn);
return false;
}
const char* service = "xyz.openbmc_project.NSM";
dbus_message_append_args(msg, DBUS_TYPE_STRING, &service,
DBUS_TYPE_INVALID);
DBusMessage* reply = dbus_connection_send_with_reply_and_block(conn, msg,
-1, nullptr);
dbus_message_unref(msg);
dbus_connection_unref(conn);
if (!reply)
return false;
dbus_bool_t hasOwner = FALSE;
dbus_message_get_args(reply, nullptr, DBUS_TYPE_BOOLEAN, &hasOwner,
DBUS_TYPE_INVALID);
dbus_message_unref(reply);
return hasOwner == TRUE;
}
int main(int argc, char** argv)
{
try
{
CLI::App app{"NSM requester tool for OpenBMC"};
// Check if nsmd is running first - prevent conflicts
if (isNsmdServiceActive())
{
std::cerr
<< "Error: NSM daemon (nsmd) is currently active.\n\n"
<< "Concurrent use of nsmtool is not permitted while nsmd is running,"
<< " as this would interrupt crucial NSM operations.\n\n"
<< "To proceed with nsmtool, please Stop the nsmd service first: systemctl stop nsmd\n\n"
<< "Note: nsmtool is intended for internal use. For production or "
<< "automated workflows, out-of-band methods are recommended.\n";
return -1;
}
app.require_subcommand(1)->ignore_case();
nsmtool::raw::registerCommand(app);
nsmtool::config::registerCommand(app);
nsmtool::diag::registerCommand(app);
nsmtool::firmware::registerCommand(app);
nsmtool::discovery::registerCommand(app);
nsmtool::telemetry::registerCommand(app);
nsmtool::passthrough::registerCommand(app);
CLI11_PARSE(app, argc, argv);
return 0;
}
catch (const std::exception& e)
{
std::cerr << e.what() << '\n';
return -1;
}
}