/* meow_ipc.c — MeowOS IPC 测试钩子(阶段 D · M0+M1;与 evtool 同定位)。 * * 向 meow_launcherd 的 AF_UNIX IPC(FRAMEWORK_DESIGN §1)发帧、收应答并打印。 * 静态 MIPS32r2 musl(用 zig-mipsel-cc 编译),qemu-mipsel 亦可用。 * * 子命令: * meow_ipc hello [version] [flags] → MSG_HELLO,期望 MSG_ACK * meow_ipc ping [app_id] → hello 别名(默认 meow_ipc) * meow_ipc query → MSG_ACT_QUERY,期望 MSG_ACT_RESULT * meow_ipc declare [...] → MSG_ACT_DECLARE,期望 MSG_ACK * 全局: * --sock 覆盖 socket 路径(默认可被 MEOW_IPC_SOCK 覆盖,再回退 /usr/data/meow_ipc.sock) */ #include #include #include #include #include #include #include #include #include #include #include "meow_ipc.h" static const char *g_sock = NULL; static void print_err(const m_err_t *e) { fprintf(stderr, "ERR 0x%x: %.*s\n", e->code, e->msg_len < 64 ? e->msg_len : 64, e->msg); } static int connect_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1); if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { fprintf(stderr, "connect %s: %s\n", path, strerror(errno)); close(fd); return -1; } return fd; } /* 发一帧(头+负载),读回一帧(头+负载)。返回应答类型;-1=失败。 */ static int xchg(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len, uint8_t *rbuf, uint32_t rcap) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION; memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &type, 2); memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &len, 4); size_t off = 0; while (off < sizeof hdr) { ssize_t w = write(fd, hdr + off, sizeof hdr - off); if (w <= 0) { perror("write hdr"); return -1; } off += (size_t)w; } if (len && payload) { size_t p = 0; while (p < len) { ssize_t w = write(fd, (const uint8_t *)payload + p, len - p); if (w <= 0) { perror("write payload"); return -1; } p += (size_t)w; } } /* read response header */ uint8_t rhdr[MEOW_IPC_HDR_LEN]; off = 0; while (off < sizeof rhdr) { ssize_t r = read(fd, rhdr + off, sizeof rhdr - off); if (r <= 0) { perror("read hdr"); return -1; } off += (size_t)r; } uint32_t rmagic, rlen; uint16_t rver, rtype; memcpy(&rmagic, rhdr, 4); memcpy(&rver, rhdr + 4, 2); memcpy(&rtype, rhdr + 6, 2); memcpy(&rlen, rhdr + 12, 4); if (rmagic != MEOW_IPC_MAGIC) { fprintf(stderr, "bad resp magic %08x\n", rmagic); return -1; } if (rver != MEOW_IPC_VERSION) { fprintf(stderr, "bad resp version %u\n", rver); return -1; } if (rlen > rcap) rlen = rcap; off = 0; while (off < rlen) { ssize_t r = read(fd, rbuf + off, rlen - off); if (r <= 0) { perror("read payload"); return -1; } off += (size_t)r; } return (int)rtype; } static int cmd_hello(const char *app_id, uint32_t version, uint32_t flags) { const char *sock = g_sock; int fd = connect_path(sock); if (fd < 0) return 1; m_hello_t h; memset(&h, 0, sizeof h); strncpy(h.app_id, app_id, MEOW_APP_ID_MAX - 1); h.version = version; h.flags = flags; uint8_t rbuf[256]; int rt = xchg(fd, MSG_HELLO, 1, &h, sizeof h, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("HELLO ok: code=%d status=%u (apps registered)\n", a.code, a.status); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "HELLO: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_query(const char *app_id, const char *activity) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_query_t q; memset(&q, 0, sizeof q); strncpy(q.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(q.activity, activity, MEOW_ACT_MAX - 1); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_QUERY, 2, &q, sizeof q, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACT_RESULT) { m_act_result_t r; memcpy(&r, rbuf, sizeof r); size_t cl = r.chain_len < MEOW_CHAIN_MAX ? r.chain_len : MEOW_CHAIN_MAX - 1; char chain[MEOW_CHAIN_MAX]; memcpy(chain, r.chain, cl); chain[cl] = 0; printf("QUERY ok: app=%s act=%s depth=%u chain=%s\n", app_id, activity, r.depth, cl ? chain : "(empty)"); return r.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "QUERY: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_declare(const char *app_id, int nent, char **ents) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_declare_t d; memset(&d, 0, sizeof d); strncpy(d.app_id, app_id, MEOW_APP_ID_MAX - 1); int n = 0; char *p = d.entries; int cap = (int)sizeof(d.entries); for (int i = 0; i < nent && n < 8; i++) { size_t l = strlen(ents[i]); if (l + 1 > (size_t)(d.entries + sizeof d.entries - p)) break; memcpy(p, ents[i], l + 1); p += l + 1; n++; } d.count = (uint16_t)n; uint32_t len = (uint32_t)(sizeof d.app_id + 2 + 2 + (p - d.entries)); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_DECLARE, 3, &d, len, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("DECLARE ok: app=%s n=%d code=%d\n", app_id, n, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "DECLARE: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_focus(const char *app_id, const char *activity) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_act_focus_t f; memset(&f, 0, sizeof f); strncpy(f.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(f.activity, activity, MEOW_ACT_MAX - 1); uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_FOCUS, 4, &f, sizeof f, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("FOCUS ok: app=%s act=%s code=%d\n", app_id, activity, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "FOCUS: unexpected resp type 0x%04x\n", rt); return 1; } static int cmd_back(void) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[256]; int rt = xchg(fd, MSG_ACT_BACK, 5, NULL, 0, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("BACK ok: code=%d\n", a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "BACK: unexpected resp type 0x%04x\n", rt); return 1; } /* M2a:推送通知 → MSG_NOTIFY,期望 MSG_NOTIFY_ACK。 */ static int cmd_notify(const char *app_id, const char *category, const char *summary, const char *body, uint32_t replaces_id, int ongoing, int media, int progress) { int fd = connect_path(g_sock); if (fd < 0) return 1; m_notify_t n; memset(&n, 0, sizeof n); strncpy(n.app_id, app_id, MEOW_APP_ID_MAX - 1); strncpy(n.category, category, sizeof n.category - 1); strncpy(n.summary, summary, sizeof n.summary - 1); if (body) strncpy(n.body, body, sizeof n.body - 1); n.replaces_id = replaces_id; n.ongoing = ongoing ? 1 : 0; n.media = media ? 1 : 0; n.progress = progress; n.expire_timeout = ongoing ? 0xFFFFFFFFu : 0; /* ONGOING 常驻 */ uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIFY, 6, &n, sizeof n, rbuf, sizeof rbuf); close(fd); if (rt == MSG_NOTIFY_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("NOTIFY ok: id=%u code=%d\n", a.status, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "NOTIFY: unexpected resp type 0x%04x\n", rt); return 1; } /* M2a:撤下通知 → MSG_NOTIFY_DISMISS,期望 MSG_ACK。 */ static int cmd_dismiss(uint32_t id) { int fd = connect_path(g_sock); if (fd < 0) return 1; uint8_t rbuf[256]; int rt = xchg(fd, MSG_NOTIFY_DISMISS, 7, &id, sizeof id, rbuf, sizeof rbuf); close(fd); if (rt == MSG_ACK) { m_ack_t a; memcpy(&a, rbuf, sizeof a); printf("DISMISS ok: id=%u code=%d\n", id, a.code); return a.code == MEOW_OK ? 0 : 1; } if (rt == MSG_ERR) { print_err((const m_err_t *)rbuf); return 1; } fprintf(stderr, "DISMISS: unexpected resp type 0x%04x\n", rt); return 1; } int main(int argc, char **argv) { const char *env = getenv("MEOW_IPC_SOCK"); g_sock = (env && env[0]) ? env : MEOW_IPC_PATH; /* parse leading global options */ 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")) { fprintf(stderr, "usage: meow_ipc [--sock ] hello|ping|query|declare ...\n"); return 0; } else break; } if (i >= argc) { fprintf(stderr, "bad args; try --help\n"); return 1; } const char *cmd = argv[i]; if (!strcmp(cmd, "hello")) { if (i + 1 >= argc) { fprintf(stderr, "hello needs \n"); return 1; } uint32_t ver = (i + 2 < argc) ? (uint32_t)strtoul(argv[i + 2], NULL, 0) : 1; uint32_t flg = (i + 3 < argc) ? (uint32_t)strtoul(argv[i + 3], NULL, 0) : 0; return cmd_hello(argv[i + 1], ver, flg); } if (!strcmp(cmd, "ping")) { const char *app = (i + 1 < argc) ? argv[i + 1] : "meow_ipc"; return cmd_hello(app, 1, 0); } if (!strcmp(cmd, "query")) { if (i + 2 >= argc) { fprintf(stderr, "query needs \n"); return 1; } return cmd_query(argv[i + 1], argv[i + 2]); } if (!strcmp(cmd, "declare")) { if (i + 2 >= argc) { fprintf(stderr, "declare needs [...]\n"); return 1; } return cmd_declare(argv[i + 1], argc - i - 2, argv + i + 2); } if (!strcmp(cmd, "focus")) { if (i + 2 >= argc) { fprintf(stderr, "focus needs \n"); return 1; } return cmd_focus(argv[i + 1], argv[i + 2]); } if (!strcmp(cmd, "back")) { return cmd_back(); } if (!strcmp(cmd, "notify")) { /* notify [body] [replaces_id] [ongoing] [media] [progress] */ if (i + 2 >= argc) { fprintf(stderr, "notify needs \n"); return 1; } const char *body = (i + 4 < argc) ? argv[i + 4] : ""; uint32_t rid = (i + 5 < argc) ? (uint32_t)strtoul(argv[i + 5], NULL, 0) : 0; int ongoing = (i + 6 < argc) ? atoi(argv[i + 6]) : 0; int media = (i + 7 < argc) ? atoi(argv[i + 7]) : 0; int progress = (i + 8 < argc) ? atoi(argv[i + 8]) : -1; return cmd_notify(argv[i + 1], argv[i + 2], argv[i + 3], body, rid, ongoing, media, progress); } if (!strcmp(cmd, "dismiss")) { if (i + 1 >= argc) { fprintf(stderr, "dismiss needs \n"); return 1; } return cmd_dismiss((uint32_t)strtoul(argv[i + 1], NULL, 0)); } fprintf(stderr, "unknown cmd %s; try --help\n", cmd); return 1; }