M2.54: 字体归MeowOS/fonts+SDK跟随+多字体+全屏?(等)+boot板载+状态栏28+亮度/音量修复+mDNS固化(meow_svcd双源+meow_mdns)+hostname=meowos+文档

This commit is contained in:
MeowOS Dev committed 2026-08-30 09:25:16 +08:00
1 parent 064635b3c4
commit 9b8a1e5c8b
13 files changed
+807 -35

No files matched your search

+83 -19
View File
@@ -8,9 +8,13 @@
* - svcd 本身极简:无 dlopen、无外部依赖,仅依赖 POSIX + Linux 基础接口,
* 交叉编译为 mipsel 静态(zig-mipsel-cc),打进固件(不入卡)。
*
* 配置来源(TF 卡,目录式):
* `$CARD/MeowOS/services.d/<name>.conf`(默认 `CARD=/usr/data/mnt/sd_0`)。
* 卡拔出 → svcd 优雅停止所托管服务并保留运行状态;插卡 → 自动重建服务。
* 配置来源(双源,目录式;板载优先):
* - 板载 `/usr/data/meow/services.d/<name>.conf`(Data 区,恒定存在,权威源);
* - TF 卡 `$CARD/MeowOS/services.d/<name>.conf`(默认 `CARD=/usr/data/mnt/sd_0`)。
* 扫描**两处都读**;同名服务**板载优先**(扫 TF 时若 name 已在板载 → 跳过 + WARN
* 「<name> 板载与 TF 都存在,采用板载」)。无双源冲突时行为不变。
* 卡拔出 → svcd 优雅停止所托管**卡上**服务并保留运行状态(板载服务视 trigger 保留);
* 插卡 → 自动重建。
*
* .conf 字段(极简 key = value,'#'/';' 注释,见 meow_svcd.md 文档):
* name / exec / args / env / enabled / restart / backoff_ms / max_restart /
@@ -60,7 +64,9 @@
/* ---- 默认路径 / 常量 ---- */
#define SVCD_CARD_DEFAULT "/usr/data/mnt/sd_0" /* TF 卡挂载点(SPEC §1.2) */
#define SVCD_SERVICES_REL "MeowOS/services.d" /* 配置目录(用户定案目录式) */
#define SVCD_SERVICES_REL "MeowOS/services.d" /* TF 配置目录(用户定案目录式) */
#define SVCD_SERVICES_BOARD "/usr/data/meow/services.d" /* 板载配置目录(首启预置/Data 区) */
#define SVCD_PATH_MAX 256 /* 服务源目录路径缓冲上限 */
#define SVCD_SOCK_DEFAULT "/tmp/meow_svcd.sock"
#define SVCD_STATUS_DEFAULT "/tmp/meow_svcd.status"
#define SVCD_PIDFILE_DEFAULT "/tmp/meow_svcd.pid"
@@ -111,6 +117,7 @@ typedef struct {
int max_restart; /* <0=无限 */
char cap[SVCD_CAP_MAX]; /* 解析保留;实装为后续任务 */
char trigger[SVCD_TRIG_STR_MAX]; /* boot|card-mount|wifi-up */
int src; /* 0=TF 卡, 1=板载(同名优先源) */
/* 运行状态 */
pid_t pid;
@@ -131,12 +138,14 @@ static int g_nsvc = 0;
/* 全局环境(可被 --card/--sock/--status 覆盖,亦读 env) */
static char g_card[256] = SVCD_CARD_DEFAULT;
static char g_board_dir[256] = SVCD_SERVICES_BOARD; /* 板载服务目录(--board/MEOW_SVCD_BOARD 可覆写) */
static char g_sock[SVCD_SOCK_PATH_MAX] = SVCD_SOCK_DEFAULT;
static char g_status[256] = SVCD_STATUS_DEFAULT;
static char g_pidfile[256] = SVCD_PIDFILE_DEFAULT;
static char g_log[256] = ""; /* 可选日志文件 */
static int g_card_present = 0;
static int g_board_online = 0; /* 板载服务目录本帧可读 */
static int g_wifi_up = 0;
static int g_shutdown = 0;
static int g_fg = 0; /* -f:前台(supervisor 托管) */
@@ -513,9 +522,9 @@ static int trigger_satisfied(const svc_t *s)
return g_card_present;
case 'w': /* wifi-up */
return g_card_present && g_wifi_up;
case 'b': /* boot:配置在卡 → 随卡存在 */
case 'b': /* boot:板载服务恒定存在,触发不依赖卡;TF 服务仍需卡 */
default:
return g_card_present;
return (s->src == 1) ? 1 : g_card_present;
}
}
@@ -570,11 +579,23 @@ static int card_present(void)
return 0; /* 同文件系统空目录 = 未挂载/未用 */
}
static int scan_directory(char out[][SVCD_NAME_MAX], int max)
static int board_services_exist(void)
{
struct stat st;
if (stat(g_board_dir, &st) != 0 || !S_ISDIR(st.st_mode)) return 0;
return 1;
}
static int name_in_list(const char *name, char list[][SVCD_NAME_MAX], int n)
{
for (int i = 0; i < n; i++)
if (strcmp(list[i], name) == 0) return i;
return -1;
}
/* 枚举某目录下的 *.conf,去除 .conf 得服务名。返回个数。 */
static int scan_conf_names(const char *dir, char out[][SVCD_NAME_MAX], int max)
{
char dir[512];
if (snprintf(dir, sizeof dir, "%s/%s", g_card, SVCD_SERVICES_REL)
>= (int)sizeof dir) return 0;
DIR *d = opendir(dir);
if (!d) return 0;
int n = 0;
@@ -593,18 +614,48 @@ static int scan_directory(char out[][SVCD_NAME_MAX], int max)
return n;
}
/* 卡存在时(初始/插入/reload)重新读配置并调和服务表。 */
/* 双源目录调和:板载(恒定存在、权威优先)先扫,卡上有则叠加扫 TF,
* 同名服务 TF 被板载屏蔽(WARN 记录)。无双源冲突时行为不变。 */
static void scan_and_reconcile(void)
{
char names[SVCD_MAX_SERVICES][SVCD_NAME_MAX];
int n = scan_directory(names, SVCD_MAX_SERVICES);
char srcdir[SVCD_MAX_SERVICES][SVCD_PATH_MAX]; /* 每服务实际 .conf 所在目录 */
int n = 0;
if (board_services_exist()) {
int nb = scan_conf_names(g_board_dir, names, SVCD_MAX_SERVICES);
for (int i = 0; i < nb; i++)
safe_strcpy(srcdir[i], sizeof srcdir[0], g_board_dir);
n = nb;
}
if (g_card_present) {
char tfdir[SVCD_PATH_MAX];
if (snprintf(tfdir, sizeof tfdir, "%s/%s", g_card, SVCD_SERVICES_REL)
< (int)sizeof tfdir) {
char tfnames[SVCD_MAX_SERVICES][SVCD_NAME_MAX];
int nt = scan_conf_names(tfdir, tfnames, SVCD_MAX_SERVICES);
for (int t = 0; t < nt; t++) {
if (name_in_list(tfnames[t], names, n) >= 0) {
svcd_log("%s 板载与 TF 都存在,采用板载", tfnames[t]);
continue;
}
if (n >= SVCD_MAX_SERVICES) {
svcd_log("service table full, drop %s", tfnames[t]); continue;
}
safe_strcpy(names[n], sizeof names[0], tfnames[t]);
safe_strcpy(srcdir[n], sizeof srcdir[0], tfdir);
n++;
}
}
}
for (int i = 0; i < g_nsvc; i++) g_svcs[i].in_config = 0;
for (int i = 0; i < n; i++) {
char path[512];
if (snprintf(path, sizeof path, "%s/%s/%s.conf", g_card, SVCD_SERVICES_REL,
names[i]) >= (int)sizeof path) continue;
if (snprintf(path, sizeof path, "%s/%s.conf", srcdir[i], names[i])
>= (int)sizeof path) continue;
int idx = find_svc(names[i]);
if (idx < 0) {
if (g_nsvc >= SVCD_MAX_SERVICES) { svcd_log("service table full, drop %s", names[i]); continue; }
@@ -612,6 +663,7 @@ static void scan_and_reconcile(void)
}
svc_t tmp;
if (load_conf(path, names[i], &tmp) != 0) { continue; }
tmp.src = (strcmp(srcdir[i], g_board_dir) == 0) ? 1 : 0;
svc_t *s = &g_svcs[idx];
/* 判定是否需重启(结构字段变化) */
@@ -692,6 +744,8 @@ static void on_card_out(void)
for (int i = 0; i < g_nsvc; i++) {
svc_t *s = &g_svcs[i];
s->restart_at_ms = 0;
/* 拔卡后 trigger 仍满足的服务(板载-boot)不随卡停止(板载服务保留,MDNS 等常驻) */
if (s->pid > 0 && trigger_satisfied(s)) continue;
if (s->pid > 0) { stop_service(s, 0, 0); }
else if (s->state == SV_RUNNING || s->state == SV_STOPPING) s->state = SV_STOPPED;
}
@@ -822,7 +876,7 @@ static void handle_connection(int fd)
} else if (strcmp(line, "status") == 0) {
cmd_status(fd);
} else if (strcmp(line, "reload") == 0) {
if (g_card_present) scan_and_reconcile();
scan_and_reconcile();
send_resp(fd, "OK\n");
} else if (sp && strcmp(line, "start") == 0) {
send_resp(fd, cmd_start(sp) == 0 ? "OK\n" : "ERR no-such-service\n");
@@ -942,12 +996,13 @@ static int start_daemon(void)
if (g_status_fd < 0) svcd_log("status file open fail: %s", strerror(errno));
else set_cloexec(g_status_fd);
/* 初始卡探测 */
/* 初始卡探测 + 板载服务目录状态 */
g_card_present = card_present();
if (g_card_present) scan_and_reconcile();
g_board_online = board_services_exist();
scan_and_reconcile(); /* 板载服务恒在,无卡也扫;卡上有则叠加扫 TF */
svcd_log("meow_svcd up: card=%s present=%d sock=%s pid=%d",
g_card, g_card_present, g_sock, (int)getpid());
svcd_log("meow_svcd up: card=%s present=%d board=%s sock=%s pid=%d",
g_card, g_card_present, g_board_dir, g_sock, (int)getpid());
struct pollfd pfds[2];
nfds_t nfds = 2;
@@ -997,6 +1052,12 @@ static int start_daemon(void)
if (present) { g_card_present = 1; svcd_log("card mounted, rebuild"); scan_and_reconcile(); }
else { g_card_present = 0; on_card_out(); }
}
int bonline = board_services_exist();
if (bonline != g_board_online) {
g_board_online = bonline;
svcd_log("board services dir %s %s, rebuild", g_board_dir, bonline ? "online" : "offline");
scan_and_reconcile();
}
}
tick_evaluate();
build_status_file();
@@ -1048,6 +1109,7 @@ static void usage(const char *argv0)
" options:\n"
" -f, --foreground stay in foreground (supervisor fork/exec 托管)\n"
" --card <path> TF card mount point (default /usr/data/mnt/sd_0)\n"
" --board <path> board services dir (default /usr/data/meow/services.d)\n"
" --sock <path> control socket (default /tmp/meow_svcd.sock)\n"
" --status <path> status file (default /tmp/meow_svcd.status)\n"
" --pidfile <path> pid file (default /tmp/meow_svcd.pid)\n"
@@ -1065,6 +1127,7 @@ int main(int argc, char **argv)
const char *a = argv[i];
if (strcmp(a, "-f") == 0 || strcmp(a, "--foreground") == 0) g_fg = 1;
else if (strcmp(a, "--card") == 0 && i + 1 < argc) safe_strcpy(g_card, sizeof g_card, argv[++i]);
else if (strcmp(a, "--board") == 0 && i + 1 < argc) safe_strcpy(g_board_dir, sizeof g_board_dir, argv[++i]);
else if (strcmp(a, "--sock") == 0 && i + 1 < argc) safe_strcpy(g_sock, sizeof g_sock, argv[++i]);
else if (strcmp(a, "--status") == 0 && i + 1 < argc) safe_strcpy(g_status, sizeof g_status, argv[++i]);
else if (strcmp(a, "--pidfile") == 0 && i + 1 < argc) safe_strcpy(g_pidfile, sizeof g_pidfile, argv[++i]);
@@ -1076,6 +1139,7 @@ int main(int argc, char **argv)
/* env 覆盖 */
const char *e;
if ((e = getenv("MEOW_SVCD_CARD")) && e[0]) safe_strcpy(g_card, sizeof g_card, e);
if ((e = getenv("MEOW_SVCD_BOARD")) && e[0]) safe_strcpy(g_board_dir, sizeof g_board_dir, e);
if ((e = getenv("MEOW_SVCD_SOCK")) && e[0]) safe_strcpy(g_sock, sizeof g_sock, e);
if ((e = getenv("MEOW_SVCD_STATUS")) && e[0]) safe_strcpy(g_status, sizeof g_status, e);
if ((e = getenv("MEOW_SVCD_LOG")) && e[0]) safe_strcpy(g_log, sizeof g_log, e);