Files
MeowOS-For-R3P2/patch_v2/meowpanel/src/mp_svcd.c
T

131 lines
5.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* mp_svcd.c — 服务表域:svcd 状态解析 + /api/svcd + 首页聚合 /api/overview。 */
#include "mp.h"
const char *svcd_bin(void)
{
const char *e = getenv("MEOW_SVCD_BIN");
if (e && e[0]) return e;
if (!access(SVCD_BIN, X_OK)) return SVCD_BIN;
return SVCD_BIN_CARD;
}
void svcd_fill(sbuf_t *s)
{
char out[16384];
char cmd[300];
snprintf(cmd, sizeof cmd, "%s status all 2>/dev/null", svcd_bin());
int code = run_cmd(cmd, out, sizeof out);
if (code != 0) { sA(s, "{\"available\":false}"); return; }
panel_strip_ansi(out);
char *toks[256];
sbuf_t svcs = {0};
int first = 1, count = 0;
char *ln = out;
while (*ln) {
char *nl = strchr(ln, '\n');
if (nl) *nl = 0;
int n = txt_tokens(ln, toks, 256);
/* 数据行:NAME STATE PID RESTART BACKOFF TRIGGER SRC EXIT EXIT_TIME EXEC...
* state=tok[1] 须为合法状态;exec=join(tok[9..n))。 */
if (n >= 10) {
const char *st = toks[1];
int is_known = (!strcmp(st,"running") || !strcmp(st,"stopped") ||
!strcmp(st,"stopping") || !strcmp(st,"disabled") || !strcmp(st,"failed"));
if (is_known) {
char exec[512];
join_tokens(toks, 9, n, exec, sizeof exec);
int restarts = 0;
{ const char *slash = strchr(toks[3], '/'); (void)slash; restarts = atoi(toks[3]); }
if (!first) sA(&svcs, ",");
first = 0; count++;
sA(&svcs, "{\"name\":"); sA_str(&svcs, toks[0]);
sA(&svcs, ",\"state\":"); sA_str(&svcs, toks[1]);
sA(&svcs, ",\"pid\":%d", atoi(toks[2]));
sA(&svcs, ",\"restart\":%d", restarts);
sA(&svcs, ",\"restart_str\":");
sA_str(&svcs, toks[3]);
sA(&svcs, ",\"backoff_ms\":%d", atoi(toks[4]));
sA(&svcs, ",\"trigger\":");
sA_str(&svcs, toks[5]);
sA(&svcs, ",\"src\":");
sA_str(&svcs, toks[6]);
sA(&svcs, ",\"exit\":");
sA_str(&svcs, toks[7]);
sA(&svcs, ",\"exit_time\":");
sA_str(&svcs, toks[8]);
sA(&svcs, ",\"exec\":");
sA_str(&svcs, exec);
sA(&svcs, "}");
}
}
if (nl) { *nl = '\n'; ln = nl + 1; } else break;
}
sA(s, "{\"available\":true,\"count\":%d,\"services\":[%s]}", count, svcs.b ? svcs.b : "");
sbuf_free(&svcs);
}
int api_svcd(int sock)
{
sbuf_t s = {0};
svcd_fill(&s);
int rc = send_json(sock, 200, s.b ? s.b : "{\"available\":false}");
sbuf_free(&s);
return rc;
}
int api_overview(int sock)
{
sbuf_t s = {0};
sA(&s, "{\"ts\":%lld,", (long long)time(NULL));
char pb[4096];
if (ipc_perf_query(0, pb, sizeof pb) == MEOW_OK && utf8_valid_n(pb, strlen(pb)))
sA(&s, "\"perf\":%s,", pb);
else sA(&s, "\"perf\":{\"available\":false},");
char pw[MEOW_IPC_MAX];
if (ipc_pm_query(0, pw, sizeof pw) == MEOW_OK && utf8_valid_n(pw, strlen(pw)))
sA(&s, "\"power\":%s,", pw);
else sA(&s, "\"power\":{\"available\":false},");
/* 最近异常耗电/充放电/亮灭屏/背光跳变事件(摘要 top2 进 overview,完整列表走 /api/power/events)。 */
{
uint32_t ecnt = 2;
char ej[MEOW_IPC_MAX];
uint16_t ert = 0;
int ert_rc = ipc_pm_send(MSG_PM_EVENTS, &ecnt, sizeof ecnt, &ert, ej, sizeof ej);
if (ert_rc > 0 && ert == MSG_PM_EVENTS_RESULT && utf8_valid_n(ej, strlen(ej)))
sA(&s, "\"events\":%s,", ej);
else
sA(&s, "\"events\":{\"available\":false},");
}
sA(&s, "\"audio\":");
audio_fill(&s);
if (net_block_fill(&s) == 0)
; /* net 块已追加(状态 + 合并的 dns 子键) */
else
sA(&s, ",\"net\":{\"available\":false}");
sA(&s, ",\"ams\":");
ams_fill(&s);
sA(&s, ",\"svcd\":");
svcd_fill(&s);
sA(&s, "}");
/* 服务端自校验:发出前 jv_parse 自查,坏了留证+回 500(防「非 JSON 响应」破页,2026-09-02 间歇性事故)
* 加严:内嵌 NUL(strlen 截断浏览器收残体)/非法 UTF-8(浏览器 JSON.parse 拒收,宽松解析器放行)*/
jv_t *chk = jv_parse(s.b ? s.b : "{}", (int)(s.b ? s.n : 2));
size_t slen = s.b ? strlen(s.b) : 0;
int nul_inside = s.b && (slen != s.n); /* 内嵌 NUL:strlen < s.n */
int utf8_bad = s.b && !utf8_valid_n(s.b, s.n);
int unbalanced = s.b && !json_strict_balanced(s.b, s.n); /* 尾随垃圾/多括号(jv_parse 容忍,浏览器不容忍) */
if (s.b && (nul_inside || utf8_bad || unbalanced)) { chk = NULL; }
if (!chk && s.b) {
FILE *df = fopen("/tmp/overview_bad.json", "w");
if (df) { fwrite(s.b, 1, s.n, df); fclose(df); }
panel_log("overview: SELF-CHECK fail (nul=%d utf8_bad=%d unbalanced=%d n=%zu strlen=%zu), raw dumped /tmp/overview_bad.json", nul_inside, utf8_bad, unbalanced, s.n, slen);
sbuf_free(&s);
return send_err(sock, 500, "INTERNAL", "overview 聚合输出未通过 JSON 自校验(原始数据已留 /tmp/overview_bad.json)");
}
if (chk) jv_free(chk);
int rc = send_json(sock, 200, s.b ? s.b : "{}");
sbuf_free(&s);
return rc;
}