blob: a23c9b3829696c6d4fe7d66b49a879a5882865b5 [file] [log] [blame] [edit]
#include "smbios_callback.h"
#include <signal.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <cerrno>
#include <cstring>
#include <fstream>
#include <string>
#include <utility>
#include "absl/log/log.h"
#include "smbios_file.h"
#include "grpcpp/server_context.h"
#include "grpcpp/support/status.h"
namespace blobs {
#define SMBIOS_INSTANCE_SIGNAL (SIGRTMIN + 5)
grpc::Status SmbiosTransferServiceImpl::SmbiosTransfer(
grpc::ServerContext* context,
const phosphor::smbios::SmbiosTransferRequest* request,
[[maybe_unused]] phosphor::smbios::SmbiosTransferResponse* response) {
LOG(INFO) << "SMBIOS gRPC server: Received transfer request";
std::string peer = context->peer();
LOG(INFO) << "Received peer identifies as: " << peer;
std::string entryPoint = request->smbios_entry_point();
std::string structureTable = request->smbios_structure_table();
LOG(INFO) << "Received on this instance number: " << instance;
LOG(INFO) << "Received SMBIOS entry point: " << entryPoint.size() << " bytes";
LOG(INFO) << "Received SMBIOS structure table: " << structureTable.size()
<< " bytes";
SmbiosEntry entry(instance, basePath_, std::move(entryPoint),
std::move(structureTable));
std::string errorMessage = entry.validate();
if (!(errorMessage.empty())) {
LOG(ERROR) << "Received SMBIOS content failed validation: " << errorMessage;
return {grpc::StatusCode::INVALID_ARGUMENT, errorMessage};
}
// The content is acceptable, write file and populate dbus object
bool accepted = acceptEntry(entry, true);
if (!accepted) {
errorMessage = "Another request already being processed!";
LOG(ERROR) << "Rejecting perfectly good request: " << errorMessage;
return {grpc::StatusCode::UNAVAILABLE, errorMessage};
}
LOG(INFO) << "Completing gRPC request: " << instance;
return grpc::Status::OK;
}
bool SmbiosTransferServiceImpl::claimLinkBusy() {
bool wasAlreadyBusy = linkBusy.test_and_set();
std::string word = wasAlreadyBusy ? "YEP!" : "Nope";
LOG(INFO) << "Checking if " << instance << " is already busy: " << word;
return wasAlreadyBusy;
}
bool SmbiosTransferServiceImpl::acceptEntry(const SmbiosEntry& entry,
bool isWrite) {
bool wasAlreadyBusy = claimLinkBusy();
// Only one request, per instance, can be completing at a time
if (wasAlreadyBusy) {
LOG(ERROR) << "Rejecting request because already busy: " << instance;
return false;
}
writeThenStart(entry, isWrite);
linkBusy.clear();
return true;
}
void SmbiosTransferServiceImpl::writeThenStart(const SmbiosEntry& entry,
bool isWrite) {
std::string fileName = entry.getFilename();
// Fork in the road 2: if file does not need writing, can skip ahead
if (isWrite) {
LOG(INFO) << "Writing file while quiescent: " << instance;
if (!(entry.saveToFile(fileName))) {
LOG(ERROR) << "Could not save SMBIOS to file: " << fileName;
return;
}
LOG(INFO) << "smbos file saved " << fileName;
}
sendSignalToSmbiosApp();
}
void SmbiosTransferServiceImpl::sendSignalToSmbiosApp() {
LOG(INFO) << "Attempting to send Signal to smbiosmdrv2app for instance "
<< instance;
std::ifstream pidFile(smbiosAppPidFile_);
if (!pidFile.is_open()) {
LOG(ERROR) << "Failed to open PID file " << smbiosAppPidFile_
<< " for reading. Cannot send SIGHUP.";
return;
}
std::string pidStr;
pidFile >> pidStr;
pidFile.close();
if (pidStr.empty()) {
LOG(ERROR) << "PID file " << smbiosAppPidFile_
<< " is empty. Cannot send signal.";
return;
}
pid_t targetPid = -1;
try {
// Use std::stoll for potentially large PIDs, then cast
targetPid = static_cast<pid_t>(std::stoll(pidStr));
if (targetPid <= 0) {
LOG(ERROR) << "Invalid PID read from " << smbiosAppPidFile_ << ": "
<< pidStr << ". Must be positive.";
return;
}
} catch (const std::invalid_argument& e) {
LOG(ERROR) << "Invalid content in PID file " << smbiosAppPidFile_ << ": '"
<< pidStr << "'. Not a number.";
return;
} catch (const std::out_of_range& e) {
LOG(ERROR) << "PID value in file " << smbiosAppPidFile_ << " ('" << pidStr
<< "') is out of range.";
return;
}
union sigval signal_data;
signal_data.sival_int = instance + 1;
LOG(INFO) << "Read PID " << targetPid << ". Sending signal "
<< SMBIOS_INSTANCE_SIGNAL << " with data " << signal_data.sival_int
<< "...";
if (sigqueue(targetPid, SMBIOS_INSTANCE_SIGNAL, signal_data) == -1) {
int sigqueue_errno = errno;
LOG(ERROR) << "Failed to send signal " << SMBIOS_INSTANCE_SIGNAL
<< " with sigqueue to PID " << targetPid
<< ". Error: " << sigqueue_errno << " ("
<< strerror(sigqueue_errno) << ")";
} else {
LOG(INFO) << "Successfully sent signal " << SMBIOS_INSTANCE_SIGNAL
<< " with data " << instance << " to PID " << targetPid << ".";
}
}
} // namespace blobs