diff --git a/patch_v2/meow_svc_perf/meow_svc_perf.c b/patch_v2/meow_svc_perf/meow_svc_perf.c index 8435687..13d2fd4 100644 --- a/patch_v2/meow_svc_perf/meow_svc_perf.c +++ b/patch_v2/meow_svc_perf/meow_svc_perf.c @@ -312,6 +312,129 @@ static void sys_kernel(char *out, int cap) out[rl] = 0; } +/* ---------------- 网络(wifi/bluetooth/hostname_local,SYSTEM 子集) ---------------- + * 单一权威源:/api/system、/api/status 的 network 段由 meow_svc_perf 聚合(SYSTEM_FRAMEWORK_SERVICES §4.1)。 + * 采集只走 popen(wpa_cli/ip/hciconfig) + /sys 只读,带超时防挂;拿不到的真实值回 null/占位,绝不编造。 + */ +/* wifi:解析 wpa_cli status;返回 connected(1/0)。ssid/ip 失败置空串(→ null)。 */ +static int net_wifi(char *ssid, size_t sscap, char *ip, size_t ipcap) +{ + ssid[0] = 0; ip[0] = 0; + int connected = 0; + char *o = popen_read_tmo(MEOW_TIMEOUT_MS, + "PATH=/bin:/sbin:/usr/bin:/usr/sbin wpa_cli status 2>/dev/null"); + if (o) { + char *ln = o; + while (ln && *ln) { + char *nl = strchr(ln, '\n'); + if (nl) *nl = 0; + if (!strncmp(ln, "wpa_state=", 10)) { if (!strcmp(ln + 10, "COMPLETED")) connected = 1; } + else if (!strncmp(ln, "ssid=", 5)) { snprintf(ssid, sscap, "%s", ln + 5); } + if (!nl) break; + ln = nl + 1; + } + free(o); + } + /* IP:ip -o -4 addr show wlan0 → "2: wlan0 inet 10.78.193.50/24 ...",取含 '.'+'/' 的 token 的 '/' 前段 */ + char *o2 = popen_read_tmo(MEOW_TIMEOUT_MS, + "PATH=/bin:/sbin:/usr/bin:/usr/sbin ip -o -4 addr show wlan0 2>/dev/null"); + if (o2) { + for (char *tk = strtok(o2, " \t"); tk; tk = strtok(NULL, " \t")) { + char *dot = strchr(tk, '.'); if (!dot) continue; + char *sl = strchr(tk, '/'); if (!sl || sl < dot) continue; + size_t len = (size_t)(sl - tk); + if (len >= ipcap) len = ipcap - 1; + memcpy(ip, tk, len); ip[len] = 0; + break; + } + free(o2); + } + return connected; +} + +/* bluetooth 段字段(不含外层 {}):available/powered/address/connected/devices。 */ +static void net_bluetooth_json(sbuf_t *s) +{ + int available = 0; + struct stat st; + if (stat("/sys/class/bluetooth/hci0", &st) == 0) available = 1; + sA(s, "\"available\":%s", available ? "true" : "false"); + /* address:/sys/class/bluetooth/hci0/address 优先,回退 hciconfig 的 BD Address */ + char addr[32] = ""; + if (available) { + read_file_txt("/sys/class/bluetooth/hci0/address", addr, sizeof addr); + if (!addr[0]) { + char *o = popen_read_tmo(MEOW_TIMEOUT_MS, + "PATH=/bin:/sbin:/usr/bin:/usr/sbin hciconfig hci0 2>/dev/null"); + if (o) { + char *p = strstr(o, "BD Address:"); + if (p) { + p += 11; /* "BD Address:" 长 11 */ + while (*p == ' ') p++; + int i = 0; + while (*p && *p != ' ' && *p != '\n' && i < (int)sizeof addr - 1) addr[i++] = *p++; + addr[i] = 0; + } + free(o); + } + } + } + sA(s, ",\"address\":"); + if (addr[0]) sA_str(s, addr); else sA(s, "null"); + /* powered:/sys/.../power(on/off)优先,文件不可读回退 hciconfig 行首 UP/DOWN */ + int powered = 0; + char pw[8] = ""; + int pwok = 0; + if (available) { + pwok = read_file_txt("/sys/class/bluetooth/hci0/power", pw, sizeof pw); + if (pwok > 0 && pw[0]) { + powered = (!strcmp(pw, "on")); + } else { + char *o = popen_read_tmo(MEOW_TIMEOUT_MS, + "PATH=/bin:/sbin:/usr/bin:/usr/sbin hciconfig hci0 2>/dev/null"); + if (o) { + char *ln = o; + while (ln && *ln) { + char *nl = strchr(ln, '\n'); + if (nl) *nl = 0; + char *q = ln; + while (*q == ' ' || *q == '\t') q++; + if (!strncmp(q, "UP", 2)) { powered = 1; break; } + if (!strncmp(q, "DOWN", 4)) { powered = 0; break; } + if (!nl) break; + ln = nl + 1; + } + free(o); + } + } + } + sA(s, ",\"powered\":%s", powered ? "true" : "false"); + /* connected/devices:无配对记录可查(/var/lib/bluetooth 空/未知)→ false/[],不编造 */ + sA(s, ",\"connected\":false,\"devices\":[]"); +} + +/* network 完整对象(含外层 {})。hostname 无效(空/"-")时 hostname_local=null。 */ +static void net_json(sbuf_t *s, const char *hostname) +{ + char ssid[64] = "", ip[64] = ""; + int wc = net_wifi(ssid, sizeof ssid, ip, sizeof ip); + sA(s, "{\"wifi\":{\"connected\":%s", wc ? "true" : "false"); + sA(s, ",\"ssid\":"); + if (ssid[0]) sA_str(s, ssid); else sA(s, "null"); + sA(s, ",\"ip\":"); + if (ip[0]) sA_str(s, ip); else sA(s, "null"); + sA(s, ",\"rssi\":null,\"bitrate_mbps\":null},\"bluetooth\":{"); + net_bluetooth_json(s); + sA(s, "},\"hostname_local\":"); + const char *hn = (hostname && hostname[0] && strcmp(hostname, "-")) ? hostname : NULL; + if (!hn) { sA(s, "null"); return; } + char hl[96]; + size_t l = strlen(hn); + if (l >= 6 && !strcmp(hn + l - 6, ".local")) snprintf(hl, sizeof hl, "%s", hn); + else snprintf(hl, sizeof hl, "%s.local", hn); + sA_str(s, hl); +} + /* ---------------- 聚合 JSON(subset 位掩码;与 MEOWPANEL_PROTOCOL §3.1 .data 对齐) ---------------- */ static int agg_json(int subset, char *out, int cap) { @@ -369,6 +492,8 @@ static int agg_json(int subset, char *out, int cap) sA(&s, ",\"kernel\":"); sA_str(&s, ker); sA(&s, ",\"arch\":"); sA_str(&s, arch); sA(&s, "}"); + /* network(wifi/bluetooth/hostname_local):SYSTEM 子集,/api/system 与 /api/status 透传 */ + SEP(); sA(&s, "\"network\":"); net_json(&s, host); } sA(&s, "}"); /* 外层闭合 */ #undef SEP