Skip to content

Commit c1cb174

Browse files
committed
feat(fnos-mount-manager): 添加 tmpfiles 支持以确保挂载点目录预创建
- 新增 tmpfiles.example.conf 和 tmpfiles.conf 配置文件用于目录创建规则 - 修改 generate 命令同时生成 fstab 区块和 tmpfiles 目录规则预览 - 在 apply 命令中添加 --tmpfiles-target 参数用于安装 tmpfiles 规则 - 更新 README.md 文档说明新的配置文件和使用注意事项 - 移除 x-mount.mkdir 选项改由 tmpfiles.d 统一管理目录创建 - 添加 status 命令错误处理的容错机制
1 parent 15db4f5 commit c1cb174

16 files changed

Lines changed: 235 additions & 59 deletions

linux/fnos/fnos-mount-manager/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
- `linux/fnos/fnos-mount-manager/disks.local.conf`: 当前机器的私有配置
99
- `linux/fnos/fnos-mount-manager/fstab.example`: 从示例配置生成的受控挂载区块预览
1010
- `linux/fnos/fnos-mount-manager/fstab`: 从本机私有配置生成的受控挂载区块预览
11+
- `linux/fnos/fnos-mount-manager/tmpfiles.example.conf`: 从示例配置生成的目录创建规则预览
12+
- `linux/fnos/fnos-mount-manager/tmpfiles.conf`: 从本机私有配置生成的目录创建规则预览
1113

12-
不要手改 `fstab.example``fstab`。这两个文件都是生成产物
14+
不要手改 `fstab.example``fstab``tmpfiles.example.conf``tmpfiles.conf`。这些文件都是生成产物
1315

1416
## 构建
1517

linux/fnos/fnos-mount-manager/commands/apply.sh

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,35 @@ FNOS_MOUNT_MANAGER_APPLY_LOADED=1
77

88
# 检查本机预览文件是否与当前 local 配置一致,防止 apply 直接跳过 generate。
99
fm_assert_local_preview_is_fresh() {
10-
local preview_path
11-
preview_path="$(fm_local_fstab_path)"
12-
[[ -f "${preview_path}" ]] || fm_die "Local preview is missing. Run generate first."
13-
14-
local temp_render
15-
temp_render="$(mktemp)"
16-
17-
fm_generate_scope "$(fm_local_config_path)" "${temp_render}" "disks.local.conf"
18-
19-
if ! cmp -s "${preview_path}" "${temp_render}"; then
20-
rm -f "${temp_render}"
10+
local fstab_preview_path
11+
local tmpfiles_preview_path
12+
fstab_preview_path="$(fm_local_fstab_path)"
13+
tmpfiles_preview_path="$(fm_local_tmpfiles_path)"
14+
[[ -f "${fstab_preview_path}" ]] || fm_die "Local preview is missing. Run generate first."
15+
[[ -f "${tmpfiles_preview_path}" ]] || fm_die "Local tmpfiles preview is missing. Run generate first."
16+
17+
local temp_fstab_render
18+
local temp_tmpfiles_render
19+
temp_fstab_render="$(mktemp)"
20+
temp_tmpfiles_render="$(mktemp)"
21+
22+
fm_generate_scope \
23+
"$(fm_local_config_path)" \
24+
"${temp_fstab_render}" \
25+
"${temp_tmpfiles_render}" \
26+
"disks.local.conf"
27+
28+
if ! cmp -s "${fstab_preview_path}" "${temp_fstab_render}"; then
29+
rm -f "${temp_fstab_render}" "${temp_tmpfiles_render}"
2130
fm_die "Local preview is stale. Run generate before apply."
2231
fi
2332

24-
rm -f "${temp_render}"
33+
if ! cmp -s "${tmpfiles_preview_path}" "${temp_tmpfiles_render}"; then
34+
rm -f "${temp_fstab_render}" "${temp_tmpfiles_render}"
35+
fm_die "Local tmpfiles preview is stale. Run generate before apply."
36+
fi
37+
38+
rm -f "${temp_fstab_render}" "${temp_tmpfiles_render}"
2539
}
2640

2741
# 确保所有受管挂载点目录存在,避免 mount 或 automount 首次触发时落到不存在路径。
@@ -35,18 +49,25 @@ fm_prepare_mountpoints() {
3549
# 处理 apply 子命令,支持通过 --target 把受控区块写到其他 fstab 文件。
3650
fm_cmd_apply() {
3751
local target="/etc/fstab"
52+
local tmpfiles_target="/etc/tmpfiles.d/fnos-mount-manager.conf"
53+
local install_tmpfiles="0"
3854

3955
while [[ $# -gt 0 ]]; do
4056
case "$1" in
4157
--target)
4258
target="$2"
4359
shift 2
4460
;;
61+
--tmpfiles-target)
62+
tmpfiles_target="$2"
63+
install_tmpfiles="1"
64+
shift 2
65+
;;
4566
--help | -h)
4667
cat <<'EOF'
47-
Usage: fnos-mount-manager apply [--target /path/to/fstab]
68+
Usage: fnos-mount-manager apply [--target /path/to/fstab] [--tmpfiles-target /path/to/tmpfiles.conf]
4869
49-
Merge the generated managed block into the target fstab file.
70+
Merge the generated managed block into the target fstab file and optionally install tmpfiles rules.
5071
EOF
5172
return 0
5273
;;
@@ -71,13 +92,22 @@ EOF
7192

7293
if [[ "${target}" == "/etc/fstab" ]]; then
7394
fm_prepare_mountpoints
95+
install_tmpfiles="1"
7496
fi
7597

7698
fm_install_file "${temp_output}" "${target}"
7799
rm -f "${temp_output}"
78100
fm_log "info" "Applied managed block to ${target}"
79101

102+
if [[ "${install_tmpfiles}" == "1" ]]; then
103+
fm_install_file "$(fm_local_tmpfiles_path)" "${tmpfiles_target}"
104+
fm_log "info" "Applied tmpfiles rules to ${tmpfiles_target}"
105+
fi
106+
80107
if [[ "${target}" == "/etc/fstab" ]] && command -v systemctl >/dev/null 2>&1; then
81108
fm_run_privileged systemctl daemon-reload
109+
if command -v systemd-tmpfiles >/dev/null 2>&1; then
110+
fm_run_privileged systemd-tmpfiles --create "${tmpfiles_target}"
111+
fi
82112
fi
83113
}

linux/fnos/fnos-mount-manager/commands/check.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,18 @@ fm_check_rendered_file() {
5757
fi
5858

5959
local temp_render
60+
local temp_tmpfiles
6061
temp_render="$(mktemp)"
62+
temp_tmpfiles="$(mktemp)"
6163

62-
fm_generate_scope "${config_path}" "${temp_render}" "${source_label}"
64+
fm_generate_scope "${config_path}" "${temp_render}" "${temp_tmpfiles}" "${source_label}"
6365

6466
if ! cmp -s "${rendered_path}" "${temp_render}"; then
6567
fm_log "error" "Rendered file is stale: ${rendered_path}"
6668
error_count_ref=$(( error_count_ref + 1 ))
6769
fi
6870

69-
rm -f "${temp_render}"
71+
rm -f "${temp_render}" "${temp_tmpfiles}"
7072
}
7173

7274
# 检查已知的 shell 登录补挂载片段,避免把副作用留在非显式命令路径里。

linux/fnos/fnos-mount-manager/commands/generate.sh

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ if [[ -n "${FNOS_MOUNT_MANAGER_GENERATE_LOADED:-}" ]]; then
55
fi
66
FNOS_MOUNT_MANAGER_GENERATE_LOADED=1
77

8-
# 把指定配置文件渲染为受控 fstab 区块预览
8+
# 把指定配置文件同时渲染为 fstab 区块预览和 tmpfiles 目录规则预览
99
fm_generate_scope() {
1010
local config_path="$1"
11-
local output_path="$2"
12-
local source_label="$3"
11+
local fstab_output_path="$2"
12+
local tmpfiles_output_path="$3"
13+
local source_label="$4"
1314

1415
fm_load_config "${config_path}"
15-
fm_render_managed_block "${source_label}" > "${output_path}"
16-
fm_log "info" "Wrote ${output_path}"
16+
fm_render_managed_block "${source_label}" > "${fstab_output_path}"
17+
fm_render_tmpfiles_entries > "${tmpfiles_output_path}"
18+
fm_log "info" "Wrote ${fstab_output_path}"
19+
fm_log "info" "Wrote ${tmpfiles_output_path}"
1720
}
1821

1922
# 处理 generate 子命令,默认同时更新 example 和 local 预览。
@@ -42,14 +45,22 @@ EOF
4245

4346
case "${scope}" in
4447
all | example)
45-
fm_generate_scope "$(fm_example_config_path)" "$(fm_example_fstab_path)" "disks.example.conf"
48+
fm_generate_scope \
49+
"$(fm_example_config_path)" \
50+
"$(fm_example_fstab_path)" \
51+
"$(fm_example_tmpfiles_path)" \
52+
"disks.example.conf"
4653
;;
4754
esac
4855

4956
case "${scope}" in
5057
all | local)
5158
if [[ -f "$(fm_local_config_path)" ]]; then
52-
fm_generate_scope "$(fm_local_config_path)" "$(fm_local_fstab_path)" "disks.local.conf"
59+
fm_generate_scope \
60+
"$(fm_local_config_path)" \
61+
"$(fm_local_fstab_path)" \
62+
"$(fm_local_tmpfiles_path)" \
63+
"disks.local.conf"
5364
elif [[ "${scope}" == "local" ]]; then
5465
fm_die "Local config not found: $(fm_local_config_path)"
5566
else

linux/fnos/fnos-mount-manager/commands/status.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ fm_print_disk_status() {
1515
local device_path
1616
device_path="$(fm_source_to_device_path "${source}")"
1717
local mounted_target=""
18-
mounted_target="$(fm_find_mount_target_for_device "${device_path}")"
18+
mounted_target="$(fm_find_mount_target_for_device "${device_path}" || true)"
1919

2020
printf '%s\n' "${name}"
2121
printf ' source: %s\n' "${source}"

linux/fnos/fnos-mount-manager/common.sh

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ fm_local_fstab_path() {
8282
printf '%s/fstab\n' "${FM_MANAGER_HOME}"
8383
}
8484

85+
# 返回示例 tmpfiles 预览文件路径。
86+
fm_example_tmpfiles_path() {
87+
printf '%s/tmpfiles.example.conf\n' "${FM_MANAGER_HOME}"
88+
}
89+
90+
# 返回本机 tmpfiles 预览文件路径。
91+
fm_local_tmpfiles_path() {
92+
printf '%s/tmpfiles.conf\n' "${FM_MANAGER_HOME}"
93+
}
94+
8595
# 返回源码入口路径,便于测试对照源码入口与构建产物。
8696
fm_source_entry_path() {
8797
printf '%s/main.sh\n' "${FM_MANAGER_HOME}"
@@ -160,7 +170,7 @@ fm_find_mount_target_for_device() {
160170
local resolved_device
161171
resolved_device="$(fm_resolve_device_path "${device_path}")"
162172

163-
findmnt -rn -S "${resolved_device}" -o TARGET 2>/dev/null | head -n 1
173+
findmnt -rn -S "${resolved_device}" -o TARGET 2>/dev/null | head -n 1 || true
164174
}
165175

166176
# 判断目标路径是否正好是一个独立挂载点,而不是仅仅位于某个已挂载父文件系统下。
@@ -171,6 +181,14 @@ fm_is_exact_mountpoint() {
171181
[[ "${mounted_target}" == "${mountpoint}" ]]
172182
}
173183

184+
# 把当前磁盘配置渲染为 tmpfiles 规则,确保开机前挂载点目录已存在。
185+
fm_render_tmpfiles_entries() {
186+
local i
187+
for (( i = 0; i < ${#FM_CONFIG_DISK_MOUNTPOINTS[@]}; i += 1 )); do
188+
printf 'd %s 0755 root root -\n' "${FM_CONFIG_DISK_MOUNTPOINTS[${i}]}"
189+
done
190+
}
191+
174192
# 生成 systemd mount/automount unit 名称,优先复用 systemd-escape 以兼容空格路径。
175193
fm_unit_name_for_path() {
176194
local path="$1"

linux/fnos/fnos-mount-manager/config.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ fm_disk_rendered_options() {
158158
local disk_options="${FM_CONFIG_DISK_OPTIONS[${index}]}"
159159
local mode="${FM_CONFIG_DISK_MODES[${index}]}"
160160
local device_timeout="${FM_CONFIG_DISK_TIMEOUTS[${index}]}"
161-
local mode_options="x-mount.mkdir=0755"
161+
local mode_options=""
162162

163163
if [[ -n "${device_timeout}" ]]; then
164164
mode_options="$(fm_merge_csv_options "${mode_options}" "x-systemd.device-timeout=${device_timeout}")"

0 commit comments

Comments
 (0)