我知道 uid(或 gid)没有共享的最大值:有些系统使用 99(Slackware,...),其他系统使用 65534(Debian,...)。
我问是否有特定的动机使用 65534 而不是 65535(0xFFFF)。谢谢。
答案1
为什么是 99?
这是不是实际上是最大值。这是一个阈值,系统帐户的 ID 以此为界,“真人”帐户的 ID 以此为界。这个阈值也是相当随意和可变的。没有理由将它设为 99,除非 100 是一个方便的整数。
这是各种密码和组数据库管理工具针对平台商定的方便的整数。例如,在 Debian 版本 7 中,和useradd
工具groupadd
会查找/etc/login.defs
算作“系统”和“用户”的 UID 和 GID 范围,后者的范围是 1000 到 60000(UID 和 GID 均如此)。
为什么是 65534?
首先因为 POSIX 系统调用中有两个广泛的约定:
- 返回值
-1
(转换为返回类型)表示错误,错误号可从errno
宏中获取。 - 输入值
-1
表示“不变”。
这些不是普遍的geteuid()
约定。请注意,例如,系统调用不可能返回错误。(进程总是具有有效的 UID。)因此无需static_cast<uid_t>(-1)
担心。但至少其中之一适用于 UID 和 GID。在setreuid()
和setregid()
系统调用中,参数表示-1
“无变化”。因此static_cast<uid_t>(-1)
和static_cast<gid_t>(-1)
不能正确用作实际 ID。
其次,因为 Linux 上的 UID 和 GID 曾经是 16 位的。
大约在世纪之交,它变为了 32 位,但它的影响仍然存在,而且实际上比乍一看更微妙。 -1
转换为 16 位无符号整数,也就是(在系统调用接口)以前的uid_t
和gid_t
,当然是 65535,正如您所观察到的。所以这不是可用的 UID 或 GID。
uid_t
但是,为了使在已切换到 32 位和 的内核上使用 16 位 API 的程序受益gid_t
,Linux 定义了“溢出 UID”和“溢出 GID”。这是因为在各个点上,由于在 16 位和 32 位之间进行转换,存在一些相当讨厌的交互。16 位程序将 UID 65536 视为超级用户,而内核却不这样做。较旧的内核将 UID 131072 视为超级用户,而应用程序代码则不这样做。
“溢出 UID”和“溢出 GID”本质上将所有大于 65535 的 32 位 UID 和 GID 映射到 16 位代码的 65534。这意味着第二值 0xFFFE 现在不能用作真正的 UID 或 GID 值。
当然,-1
转换为 32 位 UID 和 GID 类型也是无法使用的。
答案2
如果最大 UID 为 65535,则当 UID 以无符号的 16 位值存储时,没有任何值可以指示错误或未知的 UID。
答案3
系统通常保留最高无符号整数值 0xffff(如果该值被解释为有符号整数,则为 -1)以表示“无效”或“未使用”。
(0xffff 当然是 16 位。 有些系统使用 32 位 0xffffffff。)
零不能用于此目的,因为它是为 root 保留的。
(如果我没记错的话,为 root 保留 0 是 POSIX 惯例,出于兼容性原因,几乎所有其他操作系统也都遵守该惯例。)