Answers:
该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
};
这直接来自正在运行的内核。我将承担所有的信息是硬编码到它,也许除了domainname
(和事实证明,还nodename
,machine
和release
见注释)。发行字符串from uname -r
可以在编译时通过配置进行设置,但是我非常怀疑sysname字段可以使用-它是Linux内核,没有任何可能的理由使用它。
但是,由于它是开源的,因此您可以更改源代码并重新编译内核以使用所需的任何sysname。
uname
命令从系统调用中获取其信息。系统调用从何处获取其信息?(答案由其他发布者在此处提供:在编译时已在内核中进行了硬编码。)
machine
改变?它可能不会硬编码到内核中,因为它可能会适应硬件,但是可以肯定的是,它将在引导时设置,并且此后不会更改。但是不能:可以为每个进程设置(例如,报告i686
到x86_64上已处理的32位)。顺便说一句,release
也可以在某种程度上针对每个过程进行自定义(尝试setarch i686 --uname-2.6 uname -a
)。
machine
,nodename
并release
在问题中引用了注释。再一次,问题实际上不是所有这些领域。
数据存储在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);
字符串本身在include / generated / compile.h中:
#define UTS_MACHINE "x86_64"
#define UTS_VERSION "#30 SMP Fri Apr 11 00:24:23 BST 2014"
并在include / generate / utsrelease.h中:
#define UTS_RELEASE "3.14.0-v2-v"
UTS_SYSNAME可以在include / linux / uts.h中定义
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
或作为makefile中的#define
最后,主机名和域名可以由/ proc / sys / kernel / {hostname,domainname}控制。这些是每个UTS命名空间:
# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname
# hostname
test
# exit
# hostname
hell
unshare
。直到今天我还是以某种方式错过了这个命令。谢谢!
在Linux Cross Reference和您提到的帮助下/proc/sys/kernel/ostype
,我跟踪ostype
到include / 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
因此,正如内核文档所述:
调整这些值的唯一方法是重建内核
:-)
如其他地方所述,该信息与uname
syscall一起提供,该信息在运行的内核中进行了硬编码。
通常在通过Makefile编译新内核时设置版本部分:
VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =
当我有时间玩内核时,我曾经在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
对于其余数据,sys_uname
系统调用是使用宏(以非常复杂的方式)生成的, 如果您喜欢冒险,可以从这里开始。
更改此类信息的最佳方法可能是编写一个内核模块以覆盖uname
syscall。我从未这样做过,但是您可以在此页面的第4.2节中找到信息(对不起,没有直接链接)。但是请注意,该代码引用的是一个相当老的内核(现在的Linux内核具有uts
名称空间,无论它们的含义如何),因此您可能需要对其进行很多更改。
虽然我在源代码中找不到任何东西可以表明这一点,但我相信它使用了uname syscall。
man 2 uname
应该告诉您更多有关它的信息。如果真是这样,那就直接从内核获取信息并进行更改可能需要重新编译。
您可以更改二进制文件,以便自己做任何想要的事情,只需用w / e程序覆盖它即可。缺点是某些脚本依赖于该输出。
strace uname
,它将确认使用了uname
系统调用。
Rmano的答案让我有些困惑,但是通过在内核源目录的命令行中传递该Q=
选项,更容易发现真正的魔力make
。它使您可以查看详细信息,其中之一是对脚本的调用:echo "4.4.19$(/bin/sh ./scripts/setlocalversion .)"
。执行相同的代码片段将给出内核发行号4.4.19-00010-ge5dddbf
。如果查看脚本,它将确定版本控制系统中的编号,并通过运行该脚本bash -x
显示确切的过程:
+++ git rev-parse --verify --short HEAD
++ head=e5dddbf
+++ git describe --exact-match
++ '[' -z '' ']'
++ false
+++ git describe
++ atag=release/A530_os_1.0.0-10-ge5dddbf
++ echo release/A530_os_1.0.0-10-ge5dddbf
++ awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
++ git config --get svn-remote.svn.url
++ git diff-index --name-only HEAD
++ grep -qv '^scripts/package'
++ return
+ res=-00010-ge5dddbf
+ echo -00010-ge5dddbf
-00010-ge5dddbf
这显示给我的是,如果我想构建一个内核模块以与运行中的内核一起工作,那么我使用的是错误的标记发行版和错误的提交。我需要修复该问题,并至少构建DTB(make dtbs
)才能创建具有正确版本号的生成文件。
事实证明,即使那还不够。我不得不替换scripts/setlocalversion
为一个简单的方法:
#!/bin/sh
echo -0710GC0F-44F-01QA
然后重建自动生成的文件:
make Q= ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
然后我可以构建Derek Molloy的示例驱动程序,并insmod
成功完成了该工作。显然,关于Module.symvers
不在场的警告并不重要。Linux用来确定模块是否可以正常工作的所有工具都是该localversion字符串。
scripts/mkcompile_h
在v4.19中,这是一个生成的文件,include/generated/compile.h
其中包含以下几个有趣的部分/proc/version
:https : //github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h
该#<version>
部分来自.version
构建树上的文件,只要发生链接(需要更改文件/配置),该树就会递增scripts/link-vmlinux.sh
。
可以被KBUILD_BUILD_VERSION
环境变量覆盖:
if [ -z "$KBUILD_BUILD_VERSION" ]; then
VERSION=$(cat .version 2>/dev/null || echo 1)
else
VERSION=$KBUILD_BUILD_VERSION
fi
日期只是一个原始date
电话:
if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
TIMESTAMP=`date`
else
TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
fi
同样,用户名来自whoami
(KBUILD_BUILD_USER
),主机名来自hostname
(KBUILD_BUILD_HOST
)
编译器版本来自gcc -v
,似乎无法控制。
这是如何更改问题的内容版本:https : //stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot
domainname
字段由domainname
命令使用setdomainname
系统调用设置。同样,该nodename
字段由hostname
命令使用sethostname
系统调用设置。(nodename
/hostname
值可以存储在/etc/nodename
。)