清理规则删除符合条件的目录项,同时保留近期文件和排除的数据。

systemd-tmpfiles 执行创建与年龄策略

systemd-tmpfiles 用配置文件描述文件系统对象与维护规则。一条规则可以按指定模式创建目录,年龄规则则可以让旧条目符合清理条件,但只有命令实际执行对应操作,效果才会发生。这是一种有用的生命周期策略,不是连续监视器,也不是硬性存储配额。目录已经声明、清理命令曾经运行和磁盘空间始终有界,是三种不能互相替代的事实。 坏掉的样子 年龄不只是“创建文件多久了”,也不只是“多久没有修改内容”。文档中的默认规则考虑多个时间戳,包括访问与修改时间、文件状态变化时间,以及可获得的创建时间。某个参与判断的时间戳较新,就可能保留一个看起来 mtime 很老的条目。因此,为了测试而改写时间戳,也可能以意外方式改变结果;不能只观察其中一个字段就断定工具应该删除文件。 --create 和 --clean 执行不同操作。创建配置中的目录,不证明里面的旧内容已经清除。下面使用的 d 规则保留目录本身,同时让符合年龄条件的内容参与清理;其他类型有不同删除语义。不能因为都叫“清理”,就随意换成递归移除规则,否则可能把按条件删除变成完全不同的破坏性操作。 年龄清理中的 x 排除规则可以保留匹配目录及其内容,X 则只排除目录本身,没有相同的递归保护。它们也不会覆盖显式 r 或 R 删除规则。判断一次维护会删什么,必须同时阅读最终生效配置与执行操作,而不是只找到某条看起来写着“忽略”的记录,就认定其他规则都不可能影响该路径。 快速验证 在装有 systemd-tmpfiles 的一次性 Linux 环境中,以管理员身份运行下面的 Python 脚本。实测环境为 Debian 12、systemd 252.39。脚本传入一份明确配置和临时 --root,所有创建对象与删除目标都属于本次实验,不会使用当前系统平时执行的 tmpfiles 配置: from pathlib import Path from tempfile import TemporaryDirectory import os,stat,subprocess,time with TemporaryDirectory(prefix='xbcatm-tmpfiles-') as directory: root=Path(directory);config=root/'policy.conf' definition='d /work 0750 - - 1s -\nx /work/keep - - - - -\n' config.write_text(definition) def apply(action): result=subprocess.run(['systemd-tmpfiles','--root='+str(root),action,str(config)],capture_output=True,text=True,timeout=10) assert result.returncode==0,result.stderr apply('--create');work=root/'work' assert stat.S_IMODE(work.stat().st_mode)==0o750 old=work/'old';old.write_text('fixture');past=time.time()-60;os.utime(old,(past,past)) apply('--clean');assert old.exists() print('old atime and mtime alone do not satisfy the default age rule') config.write_text(definition.replace('1s','m:1s'));apply('--clean') assert not old.exists() print('explicit mtime-only age removes the same recently created file') config.write_text(definition);old.write_text('aged fixture') keep=work/'keep';keep.mkdir();(keep/'preserved').write_text('excluded fixture') outside=root/'outside';outside.write_text('outside cleanup tree') link=work/'link';link.symlink_to(outside) with old.open('rb') as retained: time.sleep(1.2) fresh=work/'fresh';fresh.write_text('recent fixture') apply('--clean') assert not old.exists() and not link.is_symlink() assert retained.read()==b'aged fixture' print('unlinked file remains readable through its already open descriptor') assert fresh.read_text()=='recent fixture' assert (keep/'preserved').read_text()=='excluded fixture' assert outside.read_text()=='outside cleanup tree' assert work.is_dir() print('aged entries removed; recent file and recursively excluded subtree remain') print('symlink removed without following it; target outside the cleaned tree survives') print('all creation and cleanup occurred in a temporary alternate root') 创建操作在临时根目录内生成模式为 0750 的 /work。随后创建一个文件,把访问与修改时间故意调到过去,默认清理仍然保留它,因为其他相关时间戳较新。仅仅回拨 mtime 和 atime,并不足以让这个文件满足完整默认年龄规则。这一对照可以解释为什么只用 touch 修改时间的测试,有时得不到想象中的删除结果。 ...

十二月 10, 2027 · 2 分钟 · XB Field Notes