diff --git a/patch_v2/meow_svc_power/meow_svc_power b/patch_v2/meow_svc_power/meow_svc_power index f0cc390..bc576ab 100755 Binary files a/patch_v2/meow_svc_power/meow_svc_power and b/patch_v2/meow_svc_power/meow_svc_power differ diff --git a/patch_v2/meow_svc_power/meow_svc_power.c b/patch_v2/meow_svc_power/meow_svc_power.c index ba362a5..b4f20d8 100644 --- a/patch_v2/meow_svc_power/meow_svc_power.c +++ b/patch_v2/meow_svc_power/meow_svc_power.c @@ -54,16 +54,22 @@ #define BATT_CAP "/sys/class/power_supply/battery/capacity" #define BATT_STATUS "/sys/class/power_supply/battery/status" #define BATT_VOLT "/sys/class/power_supply/battery/voltage_now" -#define DAC_NUMID "amixer -c 0 cget numid=%d 2>/dev/null" +#define UPGRADE_FW "/usr/data/mnt/sd_0/r3proii.upt" /* 卡根升级固件(写 mtd5 前完整性校验) */ + +/* 音量语义(与 launcher MEOW_VOL_DEFAULT/MEOW_VOL_MAX_DEFAULT、SDK MEOW_UI_VOL_* 一致): + * audio.volume 默认 60(写 DAC 映射值 0-100);audio.volume_max 默认 100(软上限 clamp)。 */ +#ifndef MEOW_VOL_DEFAULT +#define MEOW_VOL_DEFAULT 60 +#endif +#ifndef MEOW_VOL_MAX_DEFAULT +#define MEOW_VOL_MAX_DEFAULT 100 +#endif #define LINUX_REBOOT_MAGIC1 0xfee1dead #define LINUX_REBOOT_MAGIC2 672274793 /* 0x28121969 */ #define LINUX_REBOOT_CMD_RESTART 0x01234567 #define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc -#define SV_PIPE_MAX 4096 /* popen_read_tmo 上限 */ -#define SV_TIMEOUT_MS 1500 /* popen 子命令读超时 */ - static const char *g_sock = "/usr/data/meow_power.sock"; /* ---------------- 极简日志(stderr;svcd supervisor 捕获) ---------------- */ @@ -179,39 +185,68 @@ static int settings_set_int(const char *key, int val) return 0; } -/* ---------------- popen 限时读(kill 子进程防挂) ---------------- */ -static char *popen_read_tmo(int tmo_ms, const char *cmd) +/* 读 settings.conf 某 int 键:兼容落盘 "key = value"(带空格/多空格),'=' 切分、key 去首尾空白精确匹配 + * (避免 audio.volume 误配 audio.volume_max)。打开失败/键缺失/解析失败 → def。 + * 与 launcher 读循环、SDK meow_ui_vol.c meow_ui_vol_read 同款解析。 */ +static int settings_get_int_trim(const char *key, int def) { - int p[2]; - if (pipe(p) < 0) return NULL; - pid_t pid = fork(); - if (pid < 0) { close(p[0]); close(p[1]); return NULL; } - if (pid == 0) { - dup2(p[1], 1); - close(p[0]); close(p[1]); - execl("/bin/sh", "sh", "-c", cmd, (char *)0); - _exit(127); + FILE *f = fopen(SETTINGS_FILE, "r"); + if (!f) return def; + size_t kl = strlen(key); + char line[160]; + char *found = NULL; + while (fgets(line, sizeof line, f)) { + char *eq = strchr(line, '='); + if (!eq) continue; /* 非 key=value 行(注释/空行)跳过 */ + char *k = line; + while (*k == ' ' || *k == '\t') k++; /* key 左去空白 */ + long n = (long)(eq - k); + while (n > 0 && (k[n - 1] == ' ' || k[n - 1] == '\t')) n--; /* key 右去空白 */ + if ((size_t)n != kl || strncmp(k, key, kl) != 0) continue; /* key 不精确匹配 */ + found = eq + 1; /* 命中所求键 */ + break; } - close(p[1]); - fcntl(p[0], F_SETFL, fcntl(p[0], F_GETFL, 0) | O_NONBLOCK); - char *buf = malloc(SV_PIPE_MAX); - if (!buf) { close(p[0]); waitpid(pid, NULL, 0); return NULL; } - size_t off = 0; - int remain = tmo_ms; - while (remain > 0 && off < SV_PIPE_MAX - 1) { - struct pollfd pf = { p[0], POLLIN, 0 }; - int r = poll(&pf, 1, remain); - if (r < 0) { if (errno == EINTR) continue; break; } - if (r == 0) break; /* 超时 */ - ssize_t rd = read(p[0], buf + off, SV_PIPE_MAX - 1 - off); - if (rd == 0) break; /* EOF(子进程退出/关写端) */ - if (rd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; break; } - off += (size_t)rd; + fclose(f); + if (!found) return def; + while (*found == ' ' || *found == '\t') found++; /* value 左去空白;atoi 天然停于非数字 */ + return atoi(found); +} + +/* ---------------- 升级写保护(MeowOS 侧;固件只完整性校验,不签名) ---------------- + * upgrade 信号(CLI 与 IPC POWER_UPGRADE 同路径)触发写 mtd5 前先校验卡根升级固件 + * r3proii.upt(TF 卡挂载点 /usr/data/mnt/sd_0): + * 1. 存在(access F_OK)——无文件不写 mtd5; + * 2. 可读(access R_OK); + * 3. 常规文件 + 非空 + size>0(stat)——防 0 字节/损坏。 + * 校验失败 → 返回非 MEOW_OK + why 提示;调用方绝不写 mtd5、不 reboot。 + * 待补(二期):期望 md5/hash 校验——经 IPC/配置传期望值,或读卡上 MeowOS/config/ 固件 fingerprint; + * 本批只完整性(防"无文件/0 字节/损坏")。**固件不签名**(海贝官方 r3proii.upt 无签名,签名会挡自刷)。 */ +static int upgrade_fw_check(char *why, int cap) +{ + const char *path = UPGRADE_FW; + if (access(path, F_OK) < 0) { + svc_log("upgrade fw missing: %s (%s)", path, strerror(errno)); + snprintf(why, cap, "卡上无升级文件 %s", path); + return MEOW_ERR_NOENT; } - close(p[0]); - waitpid(pid, NULL, 0); - buf[off] = 0; - return buf; + if (access(path, R_OK) < 0) { + svc_log("upgrade fw unreadable: %s (%s)", path, strerror(errno)); + snprintf(why, cap, "升级文件不可读 %s", path); + return MEOW_ERR_IO; + } + struct stat st; + if (stat(path, &st) < 0) { + svc_log("upgrade fw stat fail: %s (%s)", path, strerror(errno)); + snprintf(why, cap, "升级文件状态读取失败 %s", path); + return MEOW_ERR_IO; + } + if (!S_ISREG(st.st_mode) || st.st_size <= 0) { + svc_log("upgrade fw invalid: %s size=%lld", path, (long long)st.st_size); + snprintf(why, cap, "升级文件为空或损坏 %s", path); + return MEOW_ERR_IO; + } + svc_log("upgrade fw ok: %s size=%lld", path, (long long)st.st_size); + return MEOW_OK; } /* 前置声明:CLI 用法串(cli_run 用到)。 */ @@ -349,28 +384,20 @@ static int screen_off(void) /* ---------------- DAC(CS43198) ---------------- */ /* 原机 cs43198 驱动 pwr_gpio=-1:无上电/下电控制点(sysfs/amixer),on/off 不支持。 - * status 仅报 amixer numid=1/2(L/R)当前音量上报值。 */ + * status 报**真实音量**:读板载 /usr/data/meow/settings.conf 的 audio.volume(meow_dac_vol_write + * 写入映射值 0-100),按 audio.volume_max clamp(与 launcher vol_clamp / SDK meow_ui_vol_clamp 同口径)。 + * 原 amixer -c 0 cget numid=1/2 为驱动 dummy 恒 0(不可靠),弃用——不再走 amixer 虚拟上报。 */ static int dac_status(char *out, int cap) { - char l[48] = "?", r[48] = "?"; - char *o1 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=1 2>/dev/null"); - if (o1) { - char *p = strstr(o1, ": values="); - if (p) snprintf(l, sizeof l, "%.40s", p + 9); - free(o1); - } - char *o2 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=2 2>/dev/null"); - if (o2) { - char *p = strstr(o2, ": values="); - if (p) snprintf(r, sizeof r, "%.40s", p + 9); - free(o2); - } - out[0] = 0; - cat_b(out, cap, "dac=cs43198 L="); - cat_b(out, cap, l); - cat_b(out, cap, " R="); - cat_b(out, cap, r); - cat_b(out, cap, " powerctl=unsupported(no_gpio)"); + int vol = settings_get_int_trim("audio.volume", MEOW_VOL_DEFAULT); + int vmax = settings_get_int_trim("audio.volume_max", MEOW_VOL_MAX_DEFAULT); + if (vol < 0) vol = 0; /* 硬下限 0 */ + if (vol > 100) vol = 100; /* 硬上限 100(0-100 口径) */ + if (vmax < 0) vmax = 0; /* 异常上限兜底:不进负值 */ + if (vol > vmax) vol = vmax; /* 尊重 audio.volume_max 软上限 */ + /* 左右同值(单个 DAC 声道容量;L=R=vol%);settings 读不到 → 默认 MEOW_VOL_DEFAULT(60) 即真实默认。 */ + snprintf(out, cap, "dac=cs43198 vol=%d%% L=R", vol); + svc_log("dac status: audio.volume=%d (volume_max=%d)", vol, vmax); return 0; } @@ -405,10 +432,18 @@ static int execute_action(const m_power_action_t *a, m_power_status_t *st) snprintf(st->msg, sizeof st->msg, "reboot accepted (boot=meow)"); return 1; case POWER_UPGRADE: - sync(); - st->code = MEOW_OK; - snprintf(st->msg, sizeof st->msg, "upgrade accepted"); - return 1; + { /* 写 mtd5 前先校验卡上升级固件(升级写保护);校验失败→非 OK、绝不写 mtd5/不 reboot。 */ + char why[64]; + int rc = upgrade_fw_check(why, sizeof why); + if (rc != MEOW_OK) { + st->code = rc; + snprintf(st->msg, sizeof st->msg, "upgrade rejected: %s", why); + return 0; /* 已填 st;调用方直接应答非 OK(不触发 run_system_action) */ + } + sync(); + st->code = MEOW_OK; + snprintf(st->msg, sizeof st->msg, "upgrade accepted"); + return 1; } case POWER_BACK_HIBY: write_boot_default(1); sync(); @@ -659,6 +694,12 @@ static int cli_run(int n, char **v) return 0; } if (!strcmp(cmd, "upgrade")) { + char why[64]; + int rc = upgrade_fw_check(why, sizeof why); + if (rc != MEOW_OK) { + fprintf(stderr, "upgrade aborted: %s (firmware NOT written to mtd5)\n", why); + return 1; + } enter_upgrade(); sys_reboot_do(LINUX_REBOOT_CMD_RESTART); return 0; diff --git a/patch_v2/meow_svc_power/meow_svc_power_host b/patch_v2/meow_svc_power/meow_svc_power_host index 0fa93b9..9148c36 100755 Binary files a/patch_v2/meow_svc_power/meow_svc_power_host and b/patch_v2/meow_svc_power/meow_svc_power_host differ