| #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 |