SerenityOS chmod 命令完全指南:八进制与符号模式修改文件权限
导读
本文基于 SerenityOS 操作系统的 chmod 手册页,系统讲解如何在 SerenityOS 中修改文件权限(file mode):既支持传统八进制数字模式,也支持 [ugoa][+-=][rwx...] 符号模式,并覆盖递归修改、setuid/setgid/sticky 特殊位等实战用法。文章同时结合仓库中 chmod 工具源码、权限掩码解析库 与 内核系统调用实现,从用户态到内核态还原权限修改的完整链路。读完本文,你将掌握在 SerenityOS 中精确控制文件访问权限的完整技能。
Name
chmod —— change file mode(修改文件模式)。
Synopsis
$ chmod <octal-mode> <path...>
$ chmod <mode> <path...>
<octal-mode>:八进制数字模式(如750);<mode>:符号模式(如o+r);<path...>:一个或多个目标文件路径,命令会依次处理全部路径。
在 chmod.cpp 中可以看到参数解析的实际定义:mode 是必需的位置参数,paths 是可变数量的位置参数,-R/--recursive 为可选选项。解析完成后,模式字符串被交给 Core::FilePermissionsMask::parse() 处理。
Description
chmod 将 path 中指定的所有文件的模式修改为 octal-mode(八进制)或符号表示形式。
符号表示形式的格式为 [[ugoa][+-=][rwx...],...],可以给出多个符号表达式,用逗号分隔。
符号模式语法详解
| 组成部分 | 取值 | 含义 |
|---|---|---|
用户类别 [ugoa] |
u |
file owner(文件属主) |
g |
file owning group(文件所属组) | |
o |
others(其他用户) | |
a |
all users(全部用户) | |
操作符 [+-=] |
+ |
添加权限 |
- |
移除权限 | |
= |
设置为仅包含指定权限,并取消其他权限 | |
权限位 [rwx] |
r |
read(读,对应位值 4) |
w |
write(写,对应位值 2) | |
x |
execute(执行,对应位值 1) |
几个关键规则:
- 未指定用户类别时默认
a:例如+r等价于a+r。这一点在 FilePermissionsMask.cpp 中有明确实现——当解析器遇到操作符而classes仍为 0 时,会自动补全为ClassFlag::All。 =会清空该类别其他权限:例如g=r表示组仅有读权限,之前组的写、执行权限都会被清除。X权限位:仓库实现还支持X(大写),它表示"仅对目录或已有任一执行位的文件添加执行权限"。这对应 FilePermissionsMask.cpp 中的directory_or_executable_mask机制:apply()时先判断S_ISDIR(mode) || (mode & 0111) != 0,满足条件才应用该掩码(见 FilePermissionsMask.h)。- 多组表达式用逗号分隔:解析器在遇到逗号后回到 Classes 状态重新解析下一组(见 FilePermissionsMask.cpp)。
- 错误校验:解析器对非法字符会返回明确的错误信息,例如
invalid class: expected 'u', 'g', 'o' or 'a'、invalid operation: expected '+', '-' or '='、invalid symbolic permission: expected 'r', 'w' or 'x',这些错误路径均有单元测试覆盖(见 TestLibCoreFilePermissionsMask.cpp)。
数字模式(八进制)详解
一个数字模式由 1 到 4 位数字组合而成,被省略的高位视为前导零。
- 第一位数字:选择特殊属性——set user ID(4)、set group ID(2)和 restricted deletion / sticky(1);
- 第二、三、四位数字:分别控制各用户类别的权限——属主(owner)、所属组(owning group)和其他用户(others),每类由 read(4)、write(2)和 execute(1)叠加而成。
例如 chmod 750 表示:属主为 7(rwx)、组为 5(r-x)、其他用户为 0(无权限)。
源码层面,八进制解析由 from_numeric_notation() 实现(见 FilePermissionsMask.cpp):使用 convert_to_uint_from_octal 将字符串按八进制解析为 mode_t,若超过 07777 则返回 invalid octal representation 错误。数字模式通过 assign_permissions() 直接设置写掩码并清空全部 0777 位,实现"整体替换"语义。
特殊位(setuid / setgid / sticky)行为说明
- 使用 4 位数字(如
4711、7750)时,第一位会设置特殊位:4为 setuid、2为 setgid、1为 sticky; - 使用 3 位数字(如
750)时,特殊位被清空——从源码看,assign_permissions只设置写掩码、清空 0777,且当字符串长度 ≥ 4 时会显式移除 07000 特殊位(见 FilePermissionsMask.cpp)。
这些边界行为在 TestLibCoreFilePermissionsMask.cpp 的 numeric_mask_special_bits 测试用例中有完整验证,例如 parse("7750").apply(0) == 07750、parse("0750").apply(07000) == 0750。
Options
-R,--recursive:递归修改文件模式
递归处理在 chmod.cpp 中实现:当目标是目录且开启了递归时,工具使用 Core::DirIterator(跳过 . 与 ..)遍历目录内所有条目,并对每个子项递归调用同一处理函数,因此可以正确处理嵌套目录树。任何一次递归操作失败都会累积到最终结果,最终以非零退出码报告失败。
权限修改的底层链路
理解 chmod 的底层原理有助于排查权限问题:
- 模式解析(用户态):chmod.cpp 调用
Core::FilePermissionsMask::parse(mode),该函数根据首字符是否为数字自动分派到八进制或符号解析器(见 FilePermissionsMask.cpp)。解析结果是一个由m_clear_mask(要清除的位)与m_write_mask(要设置的位)组成的掩码对象,最终通过apply(stat.st_mode)与文件现有模式运算得到新模式。 - 权限承诺(pledge):工具启动时调用
Core::System::pledge("stdio rpath fattr")(见 chmod.cpp),其中fattr承诺是执行文件属性修改类操作所必需的权限。 - 符号链接处理:
chmod对符号链接有特殊策略——除非符号链接被显式列在命令行中,否则不会处理它;且由于chmod系统调用作用于链接指向的目标文件,工具会对显式给出的符号链接使用stat()重新获取真实目标文件的模式作为修改基准(见 chmod.cpp)。 - 内核系统调用:最终通过
chmod系统调用完成修改。Kernel/Syscalls/chmod.cpp 展示了sys$chmod的实现:它校验fattrpledge、从用户空间拷贝参数、解析路径,并调用VirtualFileSystem::chmod();同文件还提供了基于文件描述符的sys$fchmod。follow_symlinks参数控制是否跟随符号链接。
Examples
# 属主拥有全部权限,组拥有读和执行权限,其他用户无任何权限:
$ chmod 750 README.md
# 将 '/bin/su' 设置为 set-uid,属主可读可写可执行,其他用户仅可执行:
# chmod 4711 /bin/su
# 为 'Source' 目录下所有文件添加其他用户的读权限:
$ chmod o+r Source/*
# 拒绝非属主的读写权限,并为属主开放全部权限:
$ chmod o-rw,g-rw,u+rwx script.sh
# 将 'script.sh' 的组权限设置为仅读:
$ chmod g=r script.sh
补充说明:
chmod 750 README.md等价于符号形式u=rwx,g=rx,o=;TestLibCoreFilePermissionsMask.cpp 中的file_permission_mask_parse测试用例验证了parse("750")与parse("u=rwx,g=rx,o-rwx")产生完全一致的 clear/write 掩码。chmod 4711 /bin/su中的4表示 setuid 位,注意原手册中该示例被注释掉,仅作演示用途。- 多组符号表达式逗号分隔的等价测试见 TestLibCoreFilePermissionsMask.cpp:
u+rw,g=rx,o-rwx的 clear 掩码为 0077、write 掩码为 0650,apply(0177)得到 0750。
退出码与错误处理
从 chmod.cpp 的实现可以看到:
- 所有路径处理成功时返回
0; - 任一路径失败(如 stat 失败、chmod 失败、递归子项失败)时返回
1,且每个失败都会向标准错误输出Could not stat '...'或Failed to change permissions of '...'形式的诊断信息。
这使得 chmod 可以安全地嵌入脚本:结合 && 或 set -e 时,权限修改失败会立即暴露,不会静默吞掉错误。
See also
三者配合使用即可完整管理 SerenityOS 中文件的属主、属组与权限三元组。系统调用层面,chown/chgrp 同样依赖 fattr pledge,与 chmod 的权限模型一致。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0632
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00