* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
* ubs-engine is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
* @file xalarm_stub.cpp
* @brief Stub implementation of xalarm system alarm library for IT testing.
*
* This shared library replaces libxalarm.so when running IT tests.
* When UBSE_IT_XALARM_FIFO_PATH is set, xalarm_get_event reads from a FIFO
* so the IT process can inject fault events that flow through the real
* syssentry SentryEventListen → UbseRasHandler::NodeFaultHandle chain.
*
* FIFO message format: <alarmId>|<paras>\n
* Example: 1003|12345\n
*
* When UBSE_IT_XALARM_FIFO_PATH is not set, falls back to the original
* behaviour (sleep 3600 and return -1) so existing tests are unaffected.
*/
#include <fcntl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#ifndef ALARM_INFO_MAX_PARAS_LEN
#define ALARM_INFO_MAX_PARAS_LEN 8192
#endif
#ifndef MAX_NUM_OF_ALARM_ID
#define MAX_NUM_OF_ALARM_ID 128
#endif
constexpr int XALARM_FIFO_LINE_MAX = ALARM_INFO_MAX_PARAS_LEN + 16;
struct alarm_subscription_info {
int id_list[MAX_NUM_OF_ALARM_ID];
unsigned int len;
};
struct alarm_msg {
unsigned short usAlarmId;
struct timeval AlarmTime;
char pucParas[ALARM_INFO_MAX_PARAS_LEN];
};
struct alarm_register {
int register_fd;
char alarm_enable_bitmap[MAX_NUM_OF_ALARM_ID];
};
* Read a delimited line from fd into buf (up to maxSize-1 bytes).
* Returns the number of bytes placed in buf (excluding NUL), or -1 on error.
* The delimiter is consumed but NOT stored in buf.
*/
static int ReadLine(int fd, char* buf, int maxSize)
{
int idx = 0;
while (idx < maxSize - 1) {
char ch = 0;
ssize_t n = read(fd, &ch, 1);
if (n <= 0) {
if (n == 0) {
break;
}
if (errno == EINTR) {
continue;
}
return -1;
}
if (ch == '\n') {
break;
}
buf[idx++] = ch;
}
buf[idx] = '\0';
return idx;
}
extern "C" {
int xalarm_report_event(unsigned short usAlarmId, char* pucParas, size_t len)
{
* 写入文件供IT测试进程读取RAS处理结果
* 文件路径: CWD/xalarm_ack_<alarmId> (daemon CWD = node work dir) */
if (pucParas != nullptr && len > 0) {
char ackPath[256];
snprintf(ackPath, sizeof(ackPath), "./xalarm_ack_%u", usAlarmId);
FILE* fp = fopen(ackPath, "w");
if (fp != nullptr) {
fwrite(pucParas, 1, len, fp);
fputc('\n', fp);
fclose(fp);
}
}
return 0;
}
int xalarm_register_event(struct alarm_register** register_info, struct alarm_subscription_info id_filter)
{
if (register_info == nullptr) {
return -1;
}
struct alarm_register* reg = static_cast<alarm_register*>(calloc(1, sizeof(alarm_register)));
if (reg == nullptr) {
return -1;
}
memset(reg, 0, sizeof(alarm_register));
reg->register_fd = -1;
const char* fifoPath = getenv("UBSE_IT_XALARM_FIFO_PATH");
if (fifoPath != nullptr && fifoPath[0] != '\0') {
if (mkfifo(fifoPath, 0666) != 0 && errno != EEXIST) {
} else {
* Open O_RDWR on Linux: does NOT block, and keeps a write-end
* reference so read() never sees a premature EOF when the
* IT helper closes its write fd.
*/
int fd = open(fifoPath, O_RDWR);
if (fd >= 0) {
reg->register_fd = fd;
}
}
}
*register_info = reg;
return 0;
}
int xalarm_get_event(struct alarm_msg* msg, struct alarm_register* register_info)
{
if (msg == nullptr || register_info == nullptr) {
return -1;
}
int fd = register_info->register_fd;
if (fd < 0) {
sleep(3600);
return -1;
}
xalarm_unregister_event closing the fd. */
for (;;) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
int sel = select(fd + 1, &rfds, nullptr, nullptr, &tv);
if (sel < 0) {
if (errno == EINTR) {
continue;
}
return -1;
}
if (sel == 0) {
if (fcntl(fd, F_GETFD) == -1 && errno == EBADF) {
return -1;
}
continue;
}
char lineBuf[XALARM_FIFO_LINE_MAX];
int lineLen = ReadLine(fd, lineBuf, sizeof(lineBuf));
if (lineLen <= 0) {
continue;
}
char* pipePos = strchr(lineBuf, '|');
if (pipePos == nullptr) {
continue;
}
*pipePos = '\0';
const char* alarmIdStr = lineBuf;
const char* parasStr = pipePos + 1;
errno = 0;
unsigned long id = strtoul(alarmIdStr, nullptr, 10);
if (errno != 0) {
continue;
}
msg->usAlarmId = static_cast<unsigned short>(id);
gettimeofday(&msg->AlarmTime, nullptr);
size_t parasLen = strlen(parasStr);
if (parasLen >= ALARM_INFO_MAX_PARAS_LEN) {
parasLen = ALARM_INFO_MAX_PARAS_LEN - 1;
}
memcpy(msg->pucParas, parasStr, parasLen);
msg->pucParas[parasLen] = '\0';
return 0;
}
}
void xalarm_unregister_event(struct alarm_register** register_info)
{
if (register_info == nullptr || *register_info == nullptr) {
return;
}
if ((*register_info)->register_fd >= 0) {
close((*register_info)->register_fd);
(*register_info)->register_fd = -1;
}
free(*register_info);
*register_info = nullptr;
}
}