Files
MeowOS-For-R3P2/patch_v2/meow_amsd/am.c
T

187 lines
5.8 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.
/* am.c — MeowOS 活动管理器用户侧 CLI(AMSD_DESIGN.md §3,安卓习惯,进固件 /usr/bin/am)。
*
* 连 amsd sock(--sock/MEOW_AMS_SOCK,默认 /usr/data/meow_ams.sock),发一条命令行,
* 读响应直到 EOF,格式化输出。root 免鉴权(读);写操作(start/kill)一期仅 root/系统身份。
*
* 子命令:
* am status → 在跑 App 表(pkg/状态/pid/运行时长/activity)
* am list → 注册表 + 状态(pkg/name/state/pid/launches/crashes)
* am history [pkg] → 事件历史(每 App 最近 8 条;无 pkg=全部)
* am start <pkg>[/<activity>] → 经 amsd→launcher 拉起
* am kill <pkg> → 经 amsd→launcher 终止(SIGTERM 语义)
*
* 编译(mipsel 静态):zig-mipsel-cc -Os -Wall -Wextra -static am.c -o am
* 宿主:gcc -Os -Wall -Wextra am.c -o am_host
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#define AMS_SOCK_DEFAULT "/usr/data/meow_ams.sock"
#define AMS_SOCK_PATH_MAX 108
#define AMS_RESP_MAX 65536
static const char *g_sock = NULL;
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;
snprintf(a.sun_path, sizeof a.sun_path, "%s", path);
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
fprintf(stderr, "connect %s: %s\n", path, strerror(errno));
close(fd);
return -1;
}
return fd;
}
/* 发送单行命令,读取响应直到 EOF,打印。返回 0=ok。 */
static int am_query(const char *cmd)
{
int fd = connect_path(g_sock);
if (fd < 0) return 1;
ssize_t w = write(fd, cmd, strlen(cmd));
(void)w;
static char resp[AMS_RESP_MAX];
size_t n = 0;
char tmp[2048];
ssize_t r;
while ((r = read(fd, tmp, sizeof tmp)) > 0) {
if (n + (size_t)r < sizeof resp - 1) { memcpy(resp + n, tmp, (size_t)r); n += (size_t)r; }
}
close(fd);
resp[n] = '\0';
fputs(resp, stdout);
return 0;
}
static int cmd_status(void)
{
return am_query("status\n");
}
static int cmd_list(void)
{
return am_query("list\n");
}
static int cmd_history(const char *pkg)
{
char line[512];
if (pkg && pkg[0])
snprintf(line, sizeof line, "history %s\n", pkg);
else
snprintf(line, sizeof line, "history\n");
return am_query(line);
}
static int cmd_start(const char *spec)
{
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
char line[800];
snprintf(line, sizeof line, "start %s\n", spec);
return am_query(line);
}
static int cmd_resolve(const char *spec)
{
/* spec: <pkg> <activity>(两参数)。 */
char line[800];
snprintf(line, sizeof line, "resolve %s\n", spec);
return am_query(line);
}
static int cmd_picker(const char *action)
{
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
char line[800];
snprintf(line, sizeof line, "picker %s\n", action);
return am_query(line);
}
static int cmd_picker_status(const char *reqid)
{
char line[800];
if (reqid && reqid[0])
snprintf(line, sizeof line, "picker-status %s\n", reqid);
else
snprintf(line, sizeof line, "picker-status\n");
return am_query(line);
}
static int cmd_kill(const char *pkg)
{
if (geteuid() != 0) { printf("ERR permission denied (root only)\n"); return 1; }
char line[800];
snprintf(line, sizeof line, "kill %s\n", pkg);
return am_query(line);
}
static void usage(const char *a0)
{
fprintf(stderr,
"usage: %s [--sock <path>] status|list|history [pkg]|start <pkg>[/<act>]|kill <pkg>\n"
" %s resolve <pkg> <activity> | picker <action> | picker-status [reqid]\n"
" --sock <path> amsd socket (default %s, or $MEOW_AMS_SOCK)\n",
a0, a0, AMS_SOCK_DEFAULT);
}
int main(int argc, char **argv)
{
const char *env = getenv("MEOW_AMS_SOCK");
g_sock = (env && env[0]) ? env : AMS_SOCK_DEFAULT;
const char *cmd = NULL;
char spec[768] = ""; /* 子命令后所有位置参数,空格拼接(resolve 需 pkg+act 两参) */
int spec_n = 0;
for (int i = 1; i < argc; i++) {
const char *a = argv[i];
if (!strcmp(a, "--sock") && i + 1 < argc) g_sock = argv[++i];
else if (!strcmp(a, "-h") || !strcmp(a, "--help")) { usage(argv[0]); return 0; }
else if (a[0] == '-') { usage(argv[0]); return 2; }
else if (!cmd) { cmd = a; }
else {
int w = snprintf(spec + spec_n, sizeof spec - spec_n, "%s%s",
spec_n ? " " : "", a);
if (w < 0) break;
spec_n += w;
if ((size_t)spec_n >= sizeof spec - 1) break;
}
}
if (!cmd) { usage(argv[0]); return 2; }
const char *arg = spec[0] ? spec : NULL;
if (!strcmp(cmd, "status")) return cmd_status();
if (!strcmp(cmd, "list")) return cmd_list();
if (!strcmp(cmd, "history")) return cmd_history(arg);
if (!strcmp(cmd, "start")) {
if (!arg) { fprintf(stderr, "start needs <pkg>[/<act>]\n"); return 2; }
return cmd_start(arg);
}
if (!strcmp(cmd, "kill")) {
if (!arg) { fprintf(stderr, "kill needs <pkg>\n"); return 2; }
return cmd_kill(arg);
}
if (!strcmp(cmd, "resolve")) {
if (!arg) { fprintf(stderr, "resolve needs <pkg> <activity>\n"); return 2; }
return cmd_resolve(arg);
}
if (!strcmp(cmd, "picker")) {
if (!arg) { fprintf(stderr, "picker needs <action>\n"); return 2; }
return cmd_picker(arg);
}
if (!strcmp(cmd, "picker-status")) {
return cmd_picker_status(arg);
}
usage(argv[0]);
return 2;
}