uname 从哪里获得它的信息?

use*_*251 48 linux source kernel

uname 真正从哪里获取信息?

我认为这应该是直截了当的。不幸的是,我找不到任何仅包含该信息的标题。

假设有人想将uname/ uname -s from的基本输出更改Linux为其他内容(本质上是重命名内核)。

他/她将如何以正确的方式(即更改源)进行操作?

V13*_*V13 29

数据存储在 init/version.c 中:

struct uts_namespace init_uts_ns = {
        .kref = {
                .refcount       = ATOMIC_INIT(2),
        },
        .name = {
                .sysname        = UTS_SYSNAME,
                .nodename       = UTS_NODENAME,
                .release        = UTS_RELEASE,
                .version        = UTS_VERSION,
                .machine        = UTS_MACHINE,
                .domainname     = UTS_DOMAINNAME,
        },
        .user_ns = &init_user_ns,
        .proc_inum = PROC_UTS_INIT_INO,
};
EXPORT_SYMBOL_GPL(init_uts_ns);
Run Code Online (Sandbox Code Playgroud)

字符串本身在 include/generated/compile.h 中:

#define UTS_MACHINE "x86_64"
#define UTS_VERSION "#30 SMP Fri Apr 11 00:24:23 BST 2014"
Run Code Online (Sandbox Code Playgroud)

并在 include/generated/utsrelease.h 中:

#define UTS_RELEASE "3.14.0-v2-v"
Run Code Online (Sandbox Code Playgroud)

UTS_SYSNAME 可以在 include/linux/uts.h 中定义

#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
Run Code Online (Sandbox Code Playgroud)

或作为makefiles中的#define

最后,主机名和域名可以由 /proc/sys/kernel/{hostname,domainname} 控制。这些是每个 UTS 命名空间:

# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname 
# hostname
test
# exit
# hostname
hell
Run Code Online (Sandbox Code Playgroud)

  • 而 `include/generated/compile.h` 由 `scripts/mkcompile_h` 生成:https://unix.stackexchange.com/a/485962/32558 (2认同)

gol*_*cks 26

uname实用程序从uname()系统调用中获取其信息。它填充这样的结构(参见man 2 uname):

       struct utsname {
           char sysname[];    /* Operating system name (e.g., "Linux") */
           char nodename[];   /* Name within "some implementation-defined
                                 network" */
           char release[];    /* Operating system release (e.g., "2.6.28") */
           char version[];    /* Operating system version */
           char machine[];    /* Hardware identifier */
       #ifdef _GNU_SOURCE
           char domainname[]; /* NIS or YP domain name */
       #endif
       };
Run Code Online (Sandbox Code Playgroud)

这直接来自正在运行的内核。我将承担所有的信息是硬编码到它,也许除了domainname(和事实证明,还nodenamemachinerelease见注释)。发布字符串 fromuname -r可以在编译时通过配置进行设置,但我非常怀疑 sysname 字段可以 - 它是 Linux 内核,没有任何理由让它使用其他任何东西。

但是,由于它是开源的,您可以更改源代码并重新编译内核以使用您想要的任何系统名称。

  • `domainname` 字段由 [`domainname`](http://www.linuxmanpages.com/man1/domainname.1.php) 命令设置,使用 [`setdomainname`](http://www.linuxmanpages .com/man2/setdomainname.2.php) 系统调用。类似地,`nodename` 字段由 [`hostname`](http://www.linuxmanpages.com/man1/domainname.1.php) 命令设置,使用 [`sethostname`](http://www .linuxmanpages.com/man2/sethostname.2.php) 系统调用。(`nodename` / `hostname` 值可能存储在 `/etc/nodename` 中。) (2认同)
  • 这是无关紧要的——问题是在哪里改变这个。所以是的,`uname` 命令从系统调用中获取信息。系统调用从哪里获取信息?(答案,由此处的其他海报提供:它在编译时在内核中进行了硬编码。) (2认同)
  • @goldilocks 为什么`machine` 会改变?它可能不会被硬编码到内核中,因为它可能会适应硬件,但肯定会在启动时设置,之后不会更改。但不是:它可以为每个进程设置(例如,将 `i686` 报告为在 x86_64 上处理的 32 位)。顺便说一下,`release` 也可以在一定程度上按进程定制(试试 `setarch i686 --uname-2.6 uname -a`)。 (2认同)

del*_*tab 8

Linux 交叉参考和您提到的帮助下/proc/sys/kernel/ostype,我跟踪ostypeinclude/linux/sysctl.h,其中有一条评论说名称是通过调用register_sysctl_table.

那么它是哪里调用的呢?一个地方是kernel/utsname_sysctl.c,其中包括include/linux/uts.h,我们可以在其中找到:

/*
 * Defines for what uname() should return 
 */
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
Run Code Online (Sandbox Code Playgroud)

因此,正如内核文档所述:

调整这些值的唯一方法是重建内核

:-)


Rma*_*ano 7

正如其他地方所评论的,该信息随uname系统调用一起提供,该信息在正在运行的内核中进行了硬编码。

版本部分通常在Makefile编译新内核时设置:

VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =
Run Code Online (Sandbox Code Playgroud)

当我有时间玩编译我的内核时,我曾经在 EXTRAVERSION 那里添加东西;这给了你uname -r 类似的东西3.4.1-mytestkernel

我不完全理解它,但我认为其余的信息Makefile也在第 944 行附近设置:

# ---------------------------------------------------------------------------

# KERNELRELEASE can change from a few different places, meaning version.h
# needs to be updated, so this check is forced on all builds

uts_len := 64
define filechk_utsrelease.h
    if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
      echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \
      exit 1;                                                         \
    fi;                                                               \
    (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";)
endef

define filechk_version.h
    (echo \#define LINUX_VERSION_CODE $(shell                         \
    expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
    echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef

$(version_h): $(srctree)/Makefile FORCE
    $(call filechk,version.h)

include/generated/utsrelease.h: include/config/kernel.release FORCE
    $(call filechk,utsrelease.h)

PHONY += headerdep
headerdep:
    $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
    $(srctree)/scripts/headerdep.pl -I$(srctree)/include
Run Code Online (Sandbox Code Playgroud)

对于其余数据,sys_uname系统调用是使用宏生成的(以一种非常复杂的方式), 如果您喜欢冒险,可以从这里开始。

可能更改此类信息的最佳方法是编写内核模块来覆盖uname系统调用;我从未这样做过,但您可以在此页面的第 4.2 节中找到信息(抱歉,没有直接链接)。但是请注意,该代码指的是一个相当旧的内核(现在 Linux 内核具有uts命名空间,无论它们是什么意思),因此您可能需要对其进行大量更改。


Liv*_*ack 2

虽然我在源代码中找不到任何内容来表明这一点,但我相信它使用了 uname 系统调用。

man 2 uname

应该告诉你更多相关信息。如果是这种情况,它会直接从内核获取信息并更改它可能需要重新编译。

您可以更改二进制文件,让您的 uname 执行您想做的任何操作,只需用您喜欢的程序重写它即可。缺点是某些脚本依赖于该输出。

  • 如果您执行“strace uname”,它将确认使用了“uname”系统调用。 (4认同)