ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SerenityOS uname(2) 系统调用指南:从 utsname 结构到内核实现的完整解析

SerenityOS uname(2) 系统调用指南:从 utsname 结构到内核实现的完整解析 SerenityOS uname(2) 系统调用指南从 utsname 结构到内核实现的完整解析【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity本文以 SerenityOS 的手册页uname(2)为核心讲解uname系统调用如何检索当前内核信息utsname结构体的五个字段含义、接口原型、返回值与错误语义并结合内核源码 uname.cpp 与 C 库封装 utsname.cpp 说明每个字段的实际填充来源。读完后可掌握如何在 SerenityOS 上获取系统名、主机名、发行版本、修订号与机器架构并理解各字段背后的内核实现机制。接口原型与头文件uname系统调用用于检索当前内核的信息并将其写入调用者提供的utsname结构体。手册页给出的原型如下见 uname(2) 手册页#include sys/utsname.h int uname(struct utsname* buf);调用时需将utsname结构体的用户态指针传入buf该结构体由内核负责填充。utsname 结构体字段定义与长度上限手册页中给出的结构体简写为五个变长成员struct utsname { char sysname[]; char nodename[]; char release[]; char version[]; char machine[]; };实际实现中各字段为定长数组长度上限由UTSNAME_ENTRY_LEN宏指定。查阅 内核 POSIX 头文件 可以看到完整定义#define UTSNAME_ENTRY_LEN 65 struct utsname { char sysname[UTSNAME_ENTRY_LEN]; char nodename[UTSNAME_ENTRY_LEN]; char release[UTSNAME_ENTRY_LEN]; char version[UTSNAME_ENTRY_LEN]; char machine[UTSNAME_ENTRY_LEN]; };即每个字段最多容纳 65 字节含结尾\0实际内容上限 64 字符。该头文件通过 LibC 的头文件 sys/utsname.h 暴露给用户态程序其中声明了int uname(struct utsname*);函数。五个字段的语义为字段含义sysname操作系统名称SerenityOS 固定为SerenityOSnodename节点名即当前主机名hostnamerelease发行版本号如1.0-dev形式的主/次版本version构建修订信息源码版本标识machine机器架构类型按编译目标架构而定返回值与错误语义成功时返回0失败时返回-1并通过errno描述错误原因。手册页列出的错误条件为EFAULTbuf不是一个可写入的用户态地址即内核无法将结果拷贝回用户内存。由于utsname的填充全部由内核内部完成正常情况下调用几乎不会失败EFAULT是唯一的典型错误路径对应参数指针非法或不可写的场景。内核侧实现各字段是如何填充的uname系统调用的内核实现位于 Kernel/Syscalls/uname.cpp入口函数为Process::sys$uname。其执行流程与字段填充逻辑如下前置条件Pledge 检查TRY(require_promise(Pledge::stdio));从源码可以看到SerenityOS 对uname系统调用施加了 Pledge 安全机制 约束调用进程必须持有stdio权限承诺否则系统调用会被拒绝。这是 SerenityOS 区别于传统 Unix 的一个特点——即便是查询类系统调用也需要显式承诺。machine由编译目标架构静态决定machine字段在编译期通过预处理器确定支持三种目标架构#if ARCH(X86_64) # define UNAME_MACHINE x86_64 #elif ARCH(AARCH64) # define UNAME_MACHINE aarch64 #elif ARCH(RISCV64) # define UNAME_MACHINE riscv64 #else # error Unknown architecture #endif即uname -m的结果直接对应内核构建时选择的架构未知架构会在编译期报错。release 与 version版本字符串的组装release与version字段分别来自两处release来自全局变量g_version_string。它在 Process.cpp 的启动初始化阶段被创建g_version_string MUST(KString::formatted({}.{}-dev, SERENITY_MAJOR_REVISION, SERENITY_MINOR_REVISION)).leak_ptr();从源码结构看release 字段呈现为主版本.次版本-dev的形式如1.0-dev其中版本号由构建系统注入的宏提供。version来自SERENITY_VERSION常量对应 generate-version-file.sh 生成的版本信息通常携带 git 提交哈希等构建修订信息。内核在填充时对两者都做了长度截断保护AK::TypedTransferu8::copy(reinterpret_castu8*(buf.release), g_version_string-bytes().data(), min(g_version_string-length(), UTSNAME_ENTRY_LEN - 1));即无论版本字符串多长最多只写入UTSNAME_ENTRY_LEN - 1个字节保证不会溢出定长数组。nodename来自进程附着的主机名上下文nodename主机名不是硬编码值而是在调用时从当前进程附着的主机名上下文动态读取m_attached_hostname_context.with( { hostname_context_ptr-buffer().with( { auto name_length name_buffer.representable_view().length(); VERIFY(name_length (UTSNAME_ENTRY_LEN - 1)); AK::TypedTransferchar::copy(reinterpret_castchar*(buf.nodename), name_buffer.representable_view().characters_without_null_termination(), name_length); buf.nodename[name_length] \0; }); });从源码结构看主机名以内核侧的共享上下文对象维护uname调用时实时读取其当前值并显式补上结尾\0主机名在用户态被修改后后续uname的结果会随之变化修改主机名的命令行工具见 hostname(8) 手册页。结果写回用户空间填充完成后通过一次用户态拷贝返回TRY(copy_to_user(user_buf, buf)); return 0;copy_to_user失败例如buf指向非法地址正是手册页中EFAULT错误的来源。系统调用在 Process.h 中的声明为ErrorOrFlatPtr sys$uname(Userspaceutsname*);C 库封装用户态如何发起调用用户态的uname()函数由 LibC 提供实现见 Userland/Libraries/LibC/utsname.cppint uname(struct utsname* buf) { int rc syscall(SC_uname, buf); __RETURN_WITH_ERRNO(rc, rc, -1); }逻辑很直接通过syscall(SC_uname, buf)发起系统调用__RETURN_WITH_ERRNO宏负责在返回值为负错误码时设置errno并返回-1成功时原样返回0。因此应用开发者只需#include sys/utsname.h并调用uname()无需关心底层系统调用号。配套命令uname(1) 的选项与示例系统调用之上的命令行工具uname用于打印内核信息其手册页见 Base/usr/share/man/man1/uname.md。用法为$ uname [-s] [-n] [-r] [-v] [-m] [-a]各选项对应utsname的字段选项作用对应字段-s打印系统名称sysname-n打印节点名主机名nodename-r打印系统发行版本release-v打印发行版本的具体修订版本version-m打印机器类型machine-a打印以上全部信息全部手册页给出的示例输出$ uname -sm Serenity x86_64可见-s打印系统名、-m打印架构与内核侧UNAME_MACHINE的定义一一对应。小结与验证方式综合手册页与源码SerenityOS 的uname(2)调用链路为应用调用 LibCuname()→SC_uname系统调用 →Process::sys$unameKernel/Syscalls/uname.cpp→ Pledge 检查、组装utsnamesysname 固定、machine 按架构、release/version 来自构建版本、nodename 实时读自主机名上下文→copy_to_user写回并返回 0。在 SerenityOS 终端中可通过uname -a验证全部字段的实际值若修改主机名后再次调用uname -n输出应同步变化这正是内核侧动态读取主机名上下文的直接体现。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表