#define _GNU_SOURCE /* 启用 struct ucred / SO_PEERCRED、asprintf 等 GNU/musl 扩展 */ /* meow_svc_power.c — MeowOS 电源管理专项子服务(SYSTEM_FRAMEWORK_SERVICES §1.2/§2.3/§2.4)。 * * 单一二进制双形态: * - svcd 以**空参**拉起(§1.3 conf `args=` 空)→ IPC 服务常驻:bind `/usr/data/meow_power.sock` * (`--sock`/`MEOW_IPC_POWER_SOCK` 可覆盖),收 MSG_HELLO→MSG_ACK、MSG_POWER_ACTION→MSG_POWER_STATUS。 * - root shell `meow_svc_power ` → 一次性 CLI(免鉴权)执行对应动作(不常驻)。 * * 动作逻辑与 launcher `power_menu.c` 的 `sys_do_reboot`/`set_boot_default_hiby`/`bootmode.sh Recovery` * **同源 0-diff 搬移**,仅入口(CLI vs IPC)与鉴权层不同。 * * 鉴权(一期基础校验):IPC 服务端受理 MSG_POWER_ACTION 前以 `SO_PEERCRED` 校验调用方 `uid==0`(root) * ——非 root 直接 `MEOW_ERR_PERM` 拒绝;完整 `os.meow.*` 包名鉴权(§5)留二期。CLI=root 免鉴权。 * * 通知转储归属(§3.2/§3.3 已定案):通知存储为 launcher 进程内存(meow_notif.c g_slots[]),服务跨进程 * 不可达——**转储由调用方 launcher 先做**,服务对关机/重启/升级一律 `sync()` 落盘,不重实现转储。 * * 编译(mipsel 静态):build_svc_power.sh;宿主编译 build_svc_power.sh host。 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "meow_ipc.h" /* 帧格式/消息号 + POWER_* 枚举 + m_power_* 负载(与 launcher 同源) */ /* ---- 路径常量(与 launcher 同源)---- */ #define FB_DEV "/dev/fb0" #define FBIOBLANK 0x4611 #define BACKLIGHT "/sys/class/backlight/backlight_pwm0/brightness" #define BACKLIGHT_POWER "/sys/class/backlight/backlight_pwm0/bl_power" #define BOOT_DEFAULT "/data/meow_boot_default" /* 0=MeowOS(默认),1=HibyOS */ #define COLD_BOOT "/data/meow_cold_boot" /* 冷启标记:1=上次关机,0=上次重启 */ #define MTD_OTA "/dev/mtd5" /* ota 标记分区(8M) */ #define SETTINGS_FILE "/usr/data/meow/settings.conf" #define SETTINGS_HDR "# meow-settings 1" #define VERSION_FILE "/etc/meowos_version" #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 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 捕获) ---------------- */ static void svc_log(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "[meow_svc_power] "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } /* ---------------- 文件小工具 ---------------- */ /* 读整个文本文件到 buf(NUL 结尾),返回字节数(不含 NUL);失败 -1。 */ static int read_file_txt(const char *path, char *buf, int cap) { int fd = open(path, O_RDONLY); if (fd < 0) return -1; int n = 0; while (n < cap - 1) { ssize_t r = read(fd, buf + n, (size_t)(cap - 1 - n)); if (r <= 0) break; n += (int)r; } close(fd); buf[n] = 0; while (n > 0 && (buf[n - 1] == '\n' || buf[n - 1] == '\r')) buf[--n] = 0; return n; } /* 读 int(atoi 首值);失败默认 def。 */ static int read_file_int_def(const char *path, int def) { char buf[32]; if (read_file_txt(path, buf, sizeof buf) <= 0) return def; char *p = buf; while (*p == ' ' || *p == '\t') p++; int v = atoi(p); return v; } static int write_file_str(const char *path, const char *s, mode_t mode) { int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); if (fd < 0) return -1; size_t l = strlen(s); ssize_t w = write(fd, s, l); int ok = (w == (ssize_t)l) ? 0 : -1; close(fd); return ok; } /* 读 settings.conf 某键值(key=value,行首忽略空白),找不到→def。 */ static int settings_get_int(const char *key, int def) { FILE *f = fopen(SETTINGS_FILE, "r"); if (!f) return def; char line[256]; int val = def, found = 0; size_t klen = strlen(key); while (fgets(line, sizeof line, f)) { char *p = line; while (*p == ' ' || *p == '\t') p++; if (strncmp(p, key, klen) == 0 && p[klen] == '=') { val = atoi(p + klen + 1); found = 1; break; } } fclose(f); return found ? val : def; } /* 更新/插入 settings.conf 某键(保留头,O_TRUNC 重写)。成功 0。 */ static int settings_set_int(const char *key, int val) { FILE *f = fopen(SETTINGS_FILE, "r"); char tmp[1024]; size_t klen = strlen(key); int found = 0; if (!f) { /* 无文件 → 新建头 + 键 */ FILE *nf = fopen(SETTINGS_FILE, "w"); if (!nf) return -1; fprintf(nf, "%s\n%s=%d\n", SETTINGS_HDR, key, val); fclose(nf); return 0; } /* 先把原文件读入 tmp(限 1KB,settings 为 KB 级小文件) */ size_t n = 0; int c; while (n < sizeof tmp - 1 && (c = fgetc(f)) != EOF) tmp[n++] = (char)c; fclose(f); tmp[n] = 0; FILE *nf = fopen(SETTINGS_FILE, "w"); if (!nf) return -1; /* 逐行写:头照抄;命中 key 行替换 */ char *save = NULL; for (char *ln = strtok_r(tmp, "\n", &save); ln; ln = strtok_r(NULL, "\n", &save)) { char *p = ln; while (*p == ' ' || *p == '\t') p++; if (strncmp(p, key, klen) == 0 && p[klen] == '=') { fprintf(nf, "%s=%d\n", key, val); found = 1; } else { fprintf(nf, "%s\n", ln); } } if (!found) fprintf(nf, "%s=%d\n", key, val); fclose(nf); return 0; } /* ---------------- popen 限时读(kill 子进程防挂) ---------------- */ static char *popen_read_tmo(int tmo_ms, const char *cmd) { 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); } 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; } close(p[0]); waitpid(pid, NULL, 0); buf[off] = 0; return buf; } /* 前置声明:CLI 用法串(cli_run 用到)。 */ static const char *cli_usage(void); /* ---------------- reboot / 关机 syscall ---------------- */ static void sys_reboot_do(int cmd) { /* 与 power_menu.c sys_do_reboot 同源:sync() 落盘 → reboot(2) syscall → 永不返回。 */ sync(); svc_log("sys_reboot_do cmd=0x%x", cmd); syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, NULL); svc_log("sys_reboot_do returned: %s", strerror(errno)); for (;;) usleep(1000); } /* ---------------- boot 默认 ---------------- */ /* 写 /data/meow_boot_default(0=MeowOS 默认 / 1=HibyOS 默认)。 */ static void write_boot_default(int v) { char b[8]; snprintf(b, sizeof b, "%d\n", v); if (write_file_str(BOOT_DEFAULT, b, 0644) < 0) svc_log("write %s fail: %s", BOOT_DEFAULT, strerror(errno)); else svc_log("boot_default=%d", v); } /* ---------------- 关机 logo ---------------- */ static void show_shutdown_logo(void) { /* 独立二进制 cmd_jpeg_display 能显图;SSH 无 fb 时重定向无害。 */ int rc = system("PATH=/bin:/sbin:/usr/bin:/usr/sbin cmd_jpeg_display /etc/shutdown_logo.jpeg >/dev/null 2>&1"); (void)rc; } /* ---------------- 升级(mtd5=ota:kernel2) ---------------- */ static void enter_upgrade(void) { int rc = system("PATH=/bin:/sbin:/usr/bin:/usr/sbin /usr/bin/bootmode.sh Recovery >/dev/null 2>&1"); (void)rc; } /* 读 /dev/mtd5 头,命中 "ota:kernel2" → 升级模式已设。 */ static int mtd_ota_is_upgrade(void) { int fd = open(MTD_OTA, O_RDONLY); if (fd < 0) return 0; char buf[16]; memset(buf, 0, sizeof buf); ssize_t n = read(fd, buf, sizeof buf - 1); close(fd); if (n <= 0) return 0; return strstr(buf, "ota:kernel2") != NULL; } /* ---------------- 有界拼接(printf 截断分析免疫;host/cross 均 0 warning) ---------------- */ static void cat_b(char *dst, size_t cap, const char *src) { size_t dl = strlen(dst); if (dl >= cap - 1) return; size_t sl = strlen(src); if (sl > cap - 1 - dl) sl = cap - 1 - dl; if (sl) memcpy(dst + dl, src, sl); dst[dl + sl] = 0; } /* ---------------- 电池/状态读组(同 util.c/about.c/bootmenu 数据源) ---------------- */ static void battery_fill(char *out, int cap) { int pct = read_file_int_def(BATT_CAP, -1); char st[32] = ""; read_file_txt(BATT_STATUS, st, sizeof st); int mv = read_file_int_def(BATT_VOLT, -1) / 1000; /* µV → mV */ if (pct < 0) { snprintf(out, cap, "battery=unknown"); return; } char one[64]; snprintf(one, sizeof one, "battery=%d%%(%s)", pct, st[0] ? st : "?"); out[0] = 0; cat_b(out, cap, one); if (mv >= 0) { char more[24]; snprintf(more, sizeof more, " %dmV", mv); cat_b(out, cap, more); } } static const char *boot_default_str(void) { int v = read_file_int_def(BOOT_DEFAULT, -1); if (v < 0) return "unknown"; return v ? "hiby" : "meow"; } static int cold_boot_flag(void) { return read_file_int_def(COLD_BOOT, -1); } static void status_fill(char *out, int cap) { char ver[32] = "-", batt[48] = ""; if (read_file_txt(VERSION_FILE, ver, sizeof ver) <= 0 || !ver[0]) snprintf(ver, sizeof ver, "-"); battery_fill(batt, sizeof batt); int cold = cold_boot_flag(); char head[96]; snprintf(head, sizeof head, "system=%s boot=%s upgrade=%s coldboot=%s ", ver, boot_default_str(), mtd_ota_is_upgrade() ? "yes" : "no", cold < 0 ? "unknown" : (cold ? "shutdown" : "reboot")); out[0] = 0; cat_b(out, cap, head); cat_b(out, cap, batt); } /* ---------------- 屏幕电源(同 launcher keys.c meow_panel_off/on + backlight.c) ---------------- */ static int backlight_write(int val) { char b[16]; snprintf(b, sizeof b, "%d", val); return write_file_str(BACKLIGHT, b, 0644) < 0 ? -1 : 0; } static int screen_on(void) { int f = open(FB_DEV, O_RDWR); if (f >= 0) { ioctl(f, FBIOBLANK, 0); close(f); } int bri = settings_get_int("display.brightness", 60); int bmin = settings_get_int("display.brightness_min", 1); if (bri < bmin) bri = bmin; if (bri > 100) bri = 100; backlight_write(bri); svc_log("screen ON (brightness %d)", bri); return 0; } static int screen_off(void) { int f = open(FB_DEV, O_RDWR); if (f >= 0) { ioctl(f, FBIOBLANK, 4); close(f); } backlight_write(0); svc_log("screen OFF (blank 4 + brightness 0)"); return 0; } /* ---------------- DAC(CS43198) ---------------- */ /* 原机 cs43198 驱动 pwr_gpio=-1:无上电/下电控制点(sysfs/amixer),on/off 不支持。 * status 仅报 amixer numid=1/2(L/R)当前音量上报值。 */ 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)"); return 0; } static int dac_cmd(const char *sub, char *out, int cap) { if (!sub) return MEOW_ERR_INVAL; if (!strcmp(sub, "status")) { return dac_status(out, cap); } if (!strcmp(sub, "on") || !strcmp(sub, "off")) { snprintf(out, cap, "DAC %s: unsupported (cs43198 pwr_gpio=-1, no on/off control point)", sub); return MEOW_ERR_NODEV; } return MEOW_ERR_INVAL; } /* ---------------- 动作执行(CLI + IPC 共用) ---------------- * 返回 0 = 已同步执行并填好 st(调用方直接应答 st 给客户端/CLI 已打印); * 返回 1 = 系统动作(关机/重启/升级/回HiBy),调用方应「先应答 MEOW_OK 受理,再执行」(执行后通常不返回)。 */ static int execute_action(const m_power_action_t *a, m_power_status_t *st) { memset(st, 0, sizeof *st); st->cmd = a->cmd; switch (a->cmd) { case POWER_SHUTDOWN: sync(); /* 通知转储由 launcher 先做;服务 sync() 落盘 */ st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "shutdown accepted"); return 1; /* 应答后:logo + poweroff(不返回) */ case POWER_REBOOT: write_boot_default(0); /* 普通重启恒回 MeowOS(无视之前) */ sync(); st->code = MEOW_OK; 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; case POWER_BACK_HIBY: write_boot_default(1); sync(); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "reboot -> hiby accepted"); return 1; case POWER_SET_DEFAULT_MEOW: write_boot_default(0); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "boot_default=meow (next boot)"); return 0; case POWER_SET_DEFAULT_HIBY: write_boot_default(1); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "boot_default=hiby (next boot)"); return 0; case POWER_STATUS: status_fill(st->msg, sizeof st->msg); st->code = MEOW_OK; return 0; case POWER_BATTERY: battery_fill(st->msg, sizeof st->msg); st->code = MEOW_OK; return 0; case POWER_REBOOT_REASON: { int c = cold_boot_flag(); snprintf(st->msg, sizeof st->msg, "coldboot=%s", c < 0 ? "unknown" : (c ? "shutdown" : "reboot")); st->code = MEOW_OK; } return 0; case POWER_UPGRADE_STATUS: snprintf(st->msg, sizeof st->msg, "upgrade=%s", mtd_ota_is_upgrade() ? "yes" : "no"); st->code = MEOW_OK; return 0; case POWER_SCREEN: if (a->flag == 0) { screen_off(); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "screen off"); return 0; } if (a->flag == 1) { screen_on(); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "screen on"); return 0; } if (a->flag == 2) { /* timeout 秒(arg) */ int sec = a->arg[0] ? atoi(a->arg) : -1; if (sec < 0 || sec > 86400) { st->code = MEOW_ERR_INVAL; snprintf(st->msg, sizeof st->msg, "screen timeout: bad sec"); return 0; } settings_set_int("display.screen_off_timeout", sec); st->code = MEOW_OK; snprintf(st->msg, sizeof st->msg, "screen_off_timeout=%ds", sec); return 0; } st->code = MEOW_ERR_INVAL; snprintf(st->msg, sizeof st->msg, "screen: bad flag"); return 0; case POWER_DAC: { int rc = dac_cmd(a->flag == 2 ? "status" : (a->flag == 1 ? "on" : "off"), st->msg, sizeof st->msg); st->code = rc; } return 0; default: st->code = MEOW_ERR_INVAL; snprintf(st->msg, sizeof st->msg, "unknown cmd %u", a->cmd); return 0; } } /* 执行「系统动作」(在应答 MEOW_OK 之后调用;通常不返回)。 */ static void run_system_action(uint32_t cmd) { switch (cmd) { case POWER_SHUTDOWN: show_shutdown_logo(); sys_reboot_do(LINUX_REBOOT_CMD_POWER_OFF); break; case POWER_REBOOT: sys_reboot_do(LINUX_REBOOT_CMD_RESTART); break; case POWER_UPGRADE: enter_upgrade(); sys_reboot_do(LINUX_REBOOT_CMD_RESTART); break; case POWER_BACK_HIBY: sys_reboot_do(LINUX_REBOOT_CMD_RESTART); break; default: break; } } /* ---------------- IPC 帧读写(同 meow_ipc 客户端约定,全小端) ---------------- */ static int x_read_full(int fd, uint8_t *buf, size_t n) { size_t off = 0; while (off < n) { ssize_t r = read(fd, buf + off, n - off); if (r <= 0) return -1; off += (size_t)r; } return 0; } static int x_write_full(int fd, const uint8_t *buf, size_t n) { size_t off = 0; while (off < n) { ssize_t w = write(fd, buf + off, n - off); if (w <= 0) return -1; off += (size_t)w; } return 0; } static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC, rlen = len; uint16_t ver = MEOW_IPC_VERSION, t = type; memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &t, 2); memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &rlen, 4); if (x_write_full(fd, hdr, MEOW_IPC_HDR_LEN) < 0) return -1; if (len && payload && x_write_full(fd, payload, len) < 0) return -1; return 0; } static int send_ack(int fd, uint32_t req_id, uint32_t code, uint32_t status) { m_ack_t a; memset(&a, 0, sizeof a); a.code = code; a.status = status; return send_frame(fd, MSG_ACK, req_id, &a, sizeof a); } static int send_err(int fd, uint32_t req_id, uint32_t code, const char *msg) { m_err_t e; memset(&e, 0, sizeof e); e.code = code; uint16_t ml = msg ? (uint16_t)strlen(msg) : 0; if (ml > 63) ml = 63; e.msg_len = ml; if (ml) memcpy(e.msg, msg, ml); return send_frame(fd, MSG_ERR, req_id, &e, sizeof e); } static int send_power_status(int fd, uint32_t req_id, const m_power_status_t *st) { m_power_status_t s = *st; uint16_t ml = (uint16_t)strlen(s.msg); if (ml >= sizeof s.msg) ml = (uint16_t)(sizeof s.msg - 1); s.msg_len = ml; return send_frame(fd, MSG_POWER_STATUS, req_id, &s, sizeof s); } /* 处理单条连接(连接内循环读帧:客户端先 MSG_HELLO 握手,再 MSG_POWER_ACTION)。 */ static void handle_conn(int c) { /* 基础鉴权:调用方 uid==0(root)才受理动作。 */ struct ucred cred; socklen_t cl = sizeof cred; int uid0 = 0; if (getsockopt(c, SOL_SOCKET, SO_PEERCRED, &cred, &cl) == 0 && cred.uid == 0) uid0 = 1; for (;;) { uint8_t hdr[MEOW_IPC_HDR_LEN]; if (x_read_full(c, hdr, sizeof hdr) < 0) break; /* EOF/错误 */ uint32_t magic, rlen, req_id; uint16_t ver, type; memcpy(&magic, hdr, 4); memcpy(&ver, hdr + 4, 2); memcpy(&type, hdr + 6, 2); memcpy(&req_id, hdr + 8, 4); memcpy(&rlen, hdr + 12, 4); if (magic != MEOW_IPC_MAGIC || ver != MEOW_IPC_VERSION) { send_err(c, req_id, MEOW_ERR_INVAL, "bad magic/ver"); break; } if (rlen > MEOW_IPC_MAX) { send_err(c, req_id, MEOW_ERR_INVAL, "payload too big"); break; } uint8_t payload[MEOW_IPC_MAX]; if (rlen && x_read_full(c, payload, rlen) < 0) break; if (type == MSG_HELLO) { send_ack(c, req_id, MEOW_OK, 0); continue; } if (type == MSG_POWER_ACTION) { m_power_action_t a; memset(&a, 0, sizeof a); if (rlen > sizeof a) rlen = sizeof a; memcpy(&a, payload, rlen); if (!uid0) { m_power_status_t st; memset(&st, 0, sizeof st); st.code = MEOW_ERR_PERM; st.cmd = a.cmd; snprintf(st.msg, sizeof st.msg, "permission denied (uid!=0)"); send_power_status(c, req_id, &st); continue; } m_power_status_t st; int act = execute_action(&a, &st); if (act == 0) { send_power_status(c, req_id, &st); continue; } /* 系统动作:先应答受理(客户端不阻塞),再执行(常不返回) */ send_power_status(c, req_id, &st); run_system_action(a.cmd); break; } send_err(c, req_id, MEOW_ERR_INVAL, "unknown type"); break; } } static int run_daemon(const char *sock) { signal(SIGPIPE, SIG_IGN); int lfd = socket(AF_UNIX, SOCK_STREAM, 0); if (lfd < 0) { svc_log("socket fail: %s", strerror(errno)); return 1; } struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, sock, sizeof a.sun_path - 1); unlink(sock); if (bind(lfd, (struct sockaddr *)&a, sizeof a) < 0) { svc_log("bind %s fail: %s", sock, strerror(errno)); close(lfd); return 1; } chmod(sock, 0666); if (listen(lfd, 8) < 0) { svc_log("listen fail: %s", strerror(errno)); close(lfd); return 1; } svc_log("meow_svc_power listening on %s", sock); for (;;) { int c = accept(lfd, NULL, NULL); if (c < 0) { if (errno == EINTR) continue; continue; } handle_conn(c); close(c); } return 0; } /* ---------------- CLI ---------------- */ static int cli_run(int n, char **v) { const char *cmd = v[0]; if (!strcmp(cmd, "shutdown")) { show_shutdown_logo(); sys_reboot_do(LINUX_REBOOT_CMD_POWER_OFF); return 0; /* 不返回 */ } if (!strcmp(cmd, "reboot")) { if (n > 1 && !strcmp(v[1], "--hiby")) { write_boot_default(1); } else write_boot_default(0); /* 普通重启恒回 MeowOS */ sys_reboot_do(LINUX_REBOOT_CMD_RESTART); return 0; } if (!strcmp(cmd, "upgrade")) { enter_upgrade(); sys_reboot_do(LINUX_REBOOT_CMD_RESTART); return 0; } if (!strcmp(cmd, "set-default-hiby")) { write_boot_default(1); printf("boot_default=hiby (next boot)\n"); return 0; } if (!strcmp(cmd, "set-default-meow")) { write_boot_default(0); printf("boot_default=meow (next boot)\n"); return 0; } if (!strcmp(cmd, "status")) { char out[128]; status_fill(out, sizeof out); printf("%s\n", out); return 0; } if (!strcmp(cmd, "battery")) { char out[64]; battery_fill(out, sizeof out); printf("%s\n", out); return 0; } if (!strcmp(cmd, "reboot-reason")) { int c = cold_boot_flag(); printf("coldboot=%s\n", c < 0 ? "unknown" : (c ? "shutdown" : "reboot")); return 0; } if (!strcmp(cmd, "upgrade-status")) { printf("upgrade=%s\n", mtd_ota_is_upgrade() ? "yes" : "no"); return 0; } if (!strcmp(cmd, "screen")) { if (n < 2) { fprintf(stderr, "screen needs on|off|timeout<秒>\n"); return 1; } if (!strcmp(v[1], "on")) return screen_on(); if (!strcmp(v[1], "off")) return screen_off(); if (!strcmp(v[1], "timeout")) { if (n < 3) { fprintf(stderr, "screen timeout needs <秒>\n"); return 1; } int sec = atoi(v[2]); if (sec < 0 || sec > 86400) { fprintf(stderr, "screen timeout: bad sec\n"); return 1; } settings_set_int("display.screen_off_timeout", sec); printf("screen_off_timeout=%ds\n", sec); return 0; } fprintf(stderr, "screen: bad sub %s\n", v[1]); return 1; } if (!strcmp(cmd, "dac")) { if (n < 2) { fprintf(stderr, "dac needs on|off|status\n"); return 1; } char out[160]; int rc = dac_cmd(v[1], out, sizeof out); printf("%s\n", out); return rc == MEOW_OK ? 0 : 1; } fprintf(stderr, "usage: meow_svc_power (%s)\n", cli_usage()); return 1; } static const char *cli_usage(void) { return "shutdown|reboot[--hiby]|upgrade|set-default-hiby|set-default-meow|" "status|battery|reboot-reason|upgrade-status|screen on|off|timeout<秒>|dac on|off|status"; } int main(int argc, char **argv) { const char *env = getenv("MEOW_IPC_POWER_SOCK"); if (env && env[0]) g_sock = env; int i = 1; for (; i < argc; i++) { if (!strcmp(argv[i], "--sock") && i + 1 < argc) g_sock = argv[++i]; else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { printf("meow_svc_power (%s)\n", cli_usage()); return 0; } else break; } if (i >= argc) return run_daemon(g_sock); /* svcd 空参 → IPC 常驻 */ return cli_run(argc - i, argv + i); }