> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/man8/mtree.8.md).

# mtree(8)

`mtree` — 映射目录层次结构

## 名称

`mtree`

## 概要

`mtree [-bCcDdejLlMnPqrStUuWx] [-i | -m] [-E tags] [-F flavor] [-f spec] [-I tags] [-K keywords] [-k keywords] [-N dbdir] [-O onlyfile] [-p path] [-R keywords] [-s seed] [-X exclude-file]`

## 描述

`mtree` 工具将文件层次结构与规范进行比较，为文件层次结构创建规范，或修改规范。

如果未被命令行选项覆盖，默认操作是将以当前目录为根的文件层次结构与从标准输入读取的规范进行比较。对于任何特征与规范不匹配的文件，或在文件层次结构或规范中缺失的文件，都会向标准输出写入消息。

选项如下：

**`-b`** 在进入和退出目录前后抑制空行。

**`-C`** 将规范转换为更易于各种工具解析的格式。输入规范从标准输入或 `-f` `spec` 指定的文件读取。在输出中，每个文件或目录使用单行表示（可能很长）。完整路径名（以 `./` 开头）始终作为第一个字段打印；`-K`、`-k` 和 `-R` 可用于控制打印哪些其他关键字；`-E` 和 `-I` 可用于控制打印哪些文件；`-S` 选项可用于对输出排序。

**`-c`** 将以当前工作目录（或 `-p` `path` 提供的目录）为根的文件层次结构的规范打印到标准输出。输出使用相对路径名的风格。

**`-D`** 与 `-C` 相同，但路径名始终作为最后一个字段而非第一个字段打印。

**`-d`** 忽略除目录类型文件外的所有内容。

**`-E`** `tags` 将逗号分隔的标签添加到"排除"列表。具有排除列表中标签的非目录项不会通过 `-C` 和 `-D` 打印。

**`-e`** 不抱怨在文件层次结构中存在但不在规范中的文件。

**`-F`** `flavor` 设置 `mtree` 工具的兼容性风格。`flavor` 可以是 `mtree`、`freebsd9` 或 `netbsd6` 之一。默认为 `mtree`。`freebsd9` 和 `netbsd6` 风格分别尝试保持与 FreeBSD 9.0 和 NetBSD 6.0 的输出兼容性和命令行选项向后兼容性。

**`-f`** `spec` 从文件 `spec` 而非标准输入读取规范。如果此选项指定两次，则将两个规范相互比较，而非与文件层次结构比较。规范将像使用 `-c` 生成的输出一样排序。这种情况下的输出格式有点像 [comm(1)](/man1/comm.1.md)，有"仅在第一个规范中"、"仅在第二个规范中"和"不同"三列，分别以零个、一个和两个 TAB 字符为前缀。"不同"列中的每个条目占两行，分别来自两个规范。

**`-I`** `tags` 将逗号分隔的标签添加到"包含"列表。具有包含列表中标签的非目录项会通过 `-C` 和 `-D` 打印。如果未提供包含列表，默认显示所有文件。

**`-i`** 如果指定，设置 `schg` 和/或 `sappnd` 标志。

**`-j`** 使用 `-c` 选项创建规范时，每深入一层目录缩进 4 个空格。这不影响 `/set` 语句或每个目录前的注释。但确实影响每个目录结束前的注释。这等同于 FreeBSD 版 `mtree` 的 `-i` 选项。

**`-K`** `keywords` 将指定的（以空格或逗号分隔）关键字添加到当前关键字集合。如果指定 `all`，则添加所有其他关键字。

**`-k`** `keywords` 使用强制的 **type** 关键字加上指定的（以空格或逗号分隔）`keywords` 替换当前关键字集合。如果指定 `all`，则使用所有可用关键字。

**`-L`** 跟随文件层次结构中的所有符号链接。

**`-l`** 进行"宽松"权限检查，其中更严格的权限将匹配较宽松的权限。例如，标记为模式 0444 的文件将通过模式 0644 的检查。"宽松"检查仅适用于读、写和执行权限——特别是，如果在规范或文件中设置了其他位（如粘滞位或 suid/sgid 位），将执行精确检查。此选项不能与 `-U` 或 `-u` 选项同时设置。

**`-M`** 允许合并不同类型的规范条目，以最后一个条目为准。

**`-m`** 如果指定了 `schg` 和/或 `sappnd` 标志，重置这些标志。请注意，这仅在安全级别低于 1 时（即单用户模式或系统运行在不安全模式时）才可能。有关安全级别的信息，请参见 [init(8)](/man8/init.8.md)。

**`-n`** 创建规范时不输出路径名注释。通常，使用 `-c` 选项时，每个目录前和该目录结束前都会输出注释。

**`-N`** `dbdir` 使用 `dbdir` 中的用户数据库文本文件 `master.passwd` 和组数据库文本文件 `group`，而非使用系统 getpwnam(3) 和 getgrnam(3)（及相关）库调用的结果。

**`-O`** `onlypaths` 仅包含此路径名列表中包含的文件。

**`-P`** 不跟随文件层次结构中的符号链接，而是在任何比较中考虑符号链接本身。这是默认行为。

**`-p`** `path` 使用以 `path` 为根的文件层次结构，而非当前目录。

**`-q`** 安静模式。当"缺失"目录因已存在而无法创建时不抱怨。这发生在目录是符号链接时。

**`-R`** `keywords` 从当前关键字集合中移除指定的（以空格或逗号分隔）关键字。**type** 关键字是强制的，始终保留。如果指定 `all`，则移除除 **type** 外的所有关键字。

**`-r`** 移除文件层次结构中未在规范中描述的任何文件。重复此标志多次将尝试通过 lchflags(2) 重置所有文件标志，然后再尝试移除文件，以防文件是不可变的。

**`-S`** 将规范读入内部数据结构时，对条目排序。排序将影响 `-C` 或 `-D` 选项产生的输出顺序，也会影响根据规范检查目录树时创建或报告缺失条目的顺序。排序顺序与 `-c` 选项使用的相同，即同一目录内的条目按 strcmp(3) 使用的顺序排序，但子目录条目排在其他条目之后。默认情况下，如果不使用 `-S` 选项，同一目录内的条目会收集在一起（与其他目录的条目分隔），但不排序。

**`-s`** `seed` 向标准错误输出显示单个校验和，表示所有指定了 **cksum** 关键字的文件。校验和使用指定值作为种子。

**`-t`** 修改现有文件的修改时间、设备的设备类型以及符号链接目标，以匹配规范。

**`-U`** 与 `-u` 相同，但不匹配如果已修正则不视为错误。

**`-u`** 修改现有文件的所有者、组、权限和标志，设备的设备类型以及符号链接目标，以匹配规范。创建任何缺失的目录、设备或符号链接。创建缺失目录必须指定用户、组和权限。请注意，除非给出 `-i` 选项，否则即使指定了 schg 和 sappnd 标志也不会设置。如果给出 `-m`，这些标志将被重置。成功时退出状态为 0，文件层次结构与规范不匹配时为 2，发生任何其他错误时为 1。

**`-W`** 创建新目录或更改现有条目时，不尝试设置各种文件属性，如所有权、模式、标志或时间。此选项与 `-U` 或 `-u` 配合使用时最有用。

**`-X`** `exclude-file` 指定的文件包含匹配要从规范中排除的文件的 fnmatch(3) 模式，每行一个。如果模式包含 `/` 字符，将与整个路径名（相对于起始目录）匹配；否则，仅与基名匹配。`exclude-file` 文件中允许注释。

**`-x`** 不深入文件层次结构中的挂载点。

规范主要由"关键字"组成，即指定与文件相关值的字符串。没有关键字具有默认值，如果关键字未设置值，则不执行基于它的检查。

当前支持的关键字如下：

**cksum** 使用 [cksum(1)](/man1/cksum.1.md) 工具指定的默认算法计算的文件校验和。

**device** 用于 **block** 或 **char** 文件类型的设备号。参数必须是以下形式之一：

* `format,major,minor` — 具有 `major` 和 `minor` 字段的设备，用于 `format` 指定的操作系统。有效格式见下文。
* `format,major,unit,subunit` — 具有 `major`、`unit` 和 `subunit` 字段的设备，用于 `format` 指定的操作系统。（目前仅 **bsdos** 格式支持。）
* `number` — 不透明数字（按文件系统存储的原样）。

`format` 可识别以下值：**native**、**386bsd**、**4bsd**、**bsdos**、**freebsd**、**hpux**、**isc**、**linux**、**netbsd**、**osf1**、**sco**、**solaris**、**sunos**、**svr3**、**svr4** 和 **ultrix**。更多详情请参见 mknod(8)。

**flags** 作为符号名称的文件标志。有关这些名称的信息，请参见 chflags(1)。如果不设置任何标志，可使用字符串 `none` 覆盖当前默认值。请注意，schg 和 sappnd 标志被特殊处理（见 `-i` 和 `-m` 选项）。

**ignore** 忽略此文件下方的任何文件层次结构。

**gid** 以数值表示的文件组。

**gname** 以符号名称表示的文件组。

**link** 符号链接预期引用的文件。

**md5** 文件的 MD5 加密消息摘要。

**md5digest** **md5** 的同义词。

**mode** 以数值（八进制）或符号值表示的当前文件权限。

**nlink** 文件预期具有的硬链接数。

**nochange** 确保此文件或目录存在，但忽略所有其他属性。

**optional** 文件是可选的；如果不在文件层次结构中，不要抱怨。

**ripemd160digest** **rmd160** 的同义词。

**rmd160** 文件的 RMD-160 加密消息摘要。

**rmd160digest** **rmd160** 的同义词。

**sha1** 文件的 SHA-1 加密消息摘要。

**sha1digest** **sha1** 的同义词。

**sha256** 文件的 256 位 SHA-2 加密消息摘要。

**sha256digest** **sha256** 的同义词。

**sha384** 文件的 384 位 SHA-2 加密消息摘要。

**sha384digest** **sha384** 的同义词。

**sha512** 文件的 512 位 SHA-2 加密消息摘要。

**sha512digest** **sha512** 的同义词。

**size** 文件的大小（以字节为单位）。

**tags** 与 `-E` 和 `-I` 匹配的逗号分隔标签。可以在指定时不带前导或尾随逗号，但在内部存储时会加上。

**time** 文件的最后修改时间，以秒和纳秒为单位。值应包含一个句点字符和句点后恰好九位数字。

**type** 文件的类型；可设为以下之一：

* **block** — 块特殊设备
* **char** — 字符特殊设备
* **dir** — 目录
* **fifo** — fifo
* **file** — 普通文件
* **link** — 符号链接
* **socket** — socket

**uid** 以数值表示的文件所有者。

**uname** 以符号名称表示的文件所有者。

默认关键字集合为 **flags**、**gid**、**link**、**mode**、**nlink**、**size**、**time**、**type** 和 **uid**。

规范中有四种类型的行：

* 为关键字设置全局值。这由字符串 `/set` 后跟空格，后跟以空格分隔的关键字/值对集合组成。关键字/值对由关键字后跟等号（`=`）后跟值组成，不含空格字符。一旦设置了关键字，其值在重置或取消设置之前保持不变。
* 取消关键字的全局值。这由字符串 `/unset` 后跟空格，后跟一个或多个以空格分隔的关键字组成。如果指定 `all`，则取消所有关键字。
* 文件规范，由路径名后跟空格，后跟零个或多个以空格分隔的关键字/值对组成。路径名前可以有空白字符。路径名可以包含任何标准路径名匹配字符（`[`、`]`、`?` 或 `*`），在这种情况下，层次结构中的文件将与它们匹配的第一个模式关联。`mtree` 使用 strsvis(3)（以 `VIS_OCTAL` 格式）对包含不可打印字符的路径名进行编码。空白字符编码为 `` `\040` ``（空格）、`` `\011` ``（制表符）和 `` `\012` ``（换行）。当选择 **netbsd6** 风格时，使用 strsvis(3)（以 `VIS_CSTYLE` 格式），空白字符编码为 `` `\s` ``（空格）、`` `\t` ``（制表符）和 `` `\n` ``（换行）。路径名中的 `#` 字符通过前缀反斜杠 `` `\` `` 进行转义，以与注释区分。每个关键字/值对由关键字后跟等号（`=`）后跟关键字值组成，不含空格字符。这些值在不更改的情况下覆盖相应关键字的全局值。列出的第一个路径名条目必须是名为 `.` 的目录，以确保完整和相对路径名混合使用时一致且正确地工作。允许名为 `.` 的目录有多个条目；最后一个此类条目的设置覆盖现有条目的设置。包含斜杠（`/`）且非首字符的路径名将被视为完整路径（相对于树根）。路径名中引用的所有父目录必须存在。相对路径名使用的当前目录路径将相应更新。如果类型相同，允许同一完整路径有多个条目（除非给出 `-M`，在这种情况下类型可以不同）；此情况下最后一个条目的设置优先。不包含斜杠的路径名将被视为相对路径。指定目录将导致后续文件在该目录层次结构中搜索。
* 仅包含字符串 `..` 的行，使当前目录路径（相对路径使用）上升一级。

空行和第一个非空白字符为井号（`#`）的行将被忽略。

`mtree` 工具成功时退出状态为 0，发生任何错误时为 1，文件层次结构与规范不匹配时为 2。

## 文件

* **/etc/mtree** 系统规范目录

## 实例

要检测已被"木马化"的系统二进制文件，建议在文件系统上运行 `mtree`，并将结果副本存储在不同的机器上，或至少以加密形式存储。`-s` 选项的种子不应是明显的值，最终校验和在任何情况下都不应在线存储！然后，定期针对在线规范运行 `mtree`，并将最终校验和与之前的值进行比较。虽然攻击者可能会更改在线规范以符合其修改后的二进制文件，但他们不应该能使它产生相同的最终校验和值。如果最终校验和值发生变化，可使用离线规范副本来检测哪些二进制文件实际被修改。

`-d` 选项可与 `-U` 或 `-u` 组合使用，例如为发行版创建目录层次结构。

## 兼容性

`-F` 选项提供的兼容性垫片在设计上是不完整的。已知限制如下所述。

**freebsd9** 风格保留了对 **uname** 和 **group** 关键字查找失败的默认处理方式，即将其替换为适当的 **uid** 和 **gid** 关键字，而非失败并报告错误。相关的 `-w` 标志是空操作，而非导致打印警告且不输出关键字。后一种行为未被模拟，因为在 /set 语句面前可能存在危险。

**netbsd6** 风格不复制历史 bug，该 bug 报告时间为 seconds.nanoseconds 格式，但对小于 100000000 的纳秒值不进行零填充。

## 参见

chflags(1), [chgrp(1)](/man1/chgrp.1.md), [chmod(1)](/man1/chmod.1.md), [cksum(1)](/man1/cksum.1.md), [stat(2)](/sys/stat.2.md), [fnmatch(3)](/gen/fnmatch.3.md), [fts(3)](/gen/fts.3.md), strsvis(3), mtree(5), [chown(8)](/man8/chown.8.md), mknod(8)

## 历史

`mtree` 工具出现于 4.3BSD Reno。**optional** 关键字出现于 NetBSD 1.2。`-U` 选项出现于 NetBSD 1.3。**flags** 和 **md5** 关键字，以及 `-i` 和 `-m` 选项出现于 NetBSD 1.4。**device**、**rmd160**、**sha1**、**tags** 和 **all** 关键字，`-D`、`-E`、`-I`、`-L`、`-l`、`-N`、`-P`、`-R`、`-W` 和 `-X` 选项，以及对完整路径的支持出现于 NetBSD 1.6。**sha256**、**sha384** 和 **sha512** 关键字出现于 NetBSD 3.0。`-S` 选项出现于 NetBSD 6.0。
