Where does uname get its information from?
Solution 1
The data is stored in 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);
The strings themselves are in include/generated/compile.h:
#define UTS_MACHINE "x86_64"
#define UTS_VERSION "#30 SMP Fri Apr 11 00:24:23 BST 2014"
and in include/generated/utsrelease.h:
#define UTS_RELEASE "3.14.0-v2-v"
UTS_SYSNAME may be defined in include/linux/uts.h
#ifndef UTS_SYSNAME
#define UTS_SYSNAME "Linux"
#endif
or as a #define in makefiles
Finally, the hostname and domainname can be controlled by /proc/sys/kernel/{hostname,domainname}. These are per UTS namespace:
# hostname
hell
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname
# hostname
test
# exit
# hostname
hell
Solution 2
The uname
utility gets its information from the uname()
system call. It populates a struct like this (see 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
};
This comes directly from the running kernel. I would assume all of the information is hard-coded into it, except perhaps domainname
(and as it turns out, also nodename
, machine
, and release
, see comments). The release string, from uname -r
, can be set via configuration at compile time, but I doubt very much the sysname field can -- it's the Linux kernel and there's no conceivable reason for it to use anything else.
However, since it is open source, you could change the source code and recompile the kernel to use whatever sysname you want.
Solution 3
With the help of a Linux Cross Reference and your mention of /proc/sys/kernel/ostype
, I tracked ostype
to include/linux/sysctl.h,
where a comment says that names are added by calling register_sysctl_table
.
So where is that called from? One place is kernel/utsname_sysctl.c, which includes include/linux/uts.h, where we find:
/* * Defines for what uname() should return */ #ifndef UTS_SYSNAME #define UTS_SYSNAME "Linux" #endif
So, as the kernel documentation states:
The only way to tune these values is to rebuild the kernel
:-)
Solution 4
As commented elsewhere, the information come with the uname
syscall, which information is hard-coded in the running kernel.
The version part is normally set when compiling a new kernel by the Makefile:
VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =
when I had time to play compiling my kernels, I used to add things over there in EXTRAVERSION; that gave you uname -r
with things like 3.4.1-mytestkernel
.
I do not fully understand it, but I think that the rest of the information is setup in the Makefile
also around line 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
For the rest of the data, the sys_uname
syscall is generated using macros (in a quite convoluted way), you can start from here if you feel adventurous.
Probably the best way to change such information is writing a kernel module to override the uname
syscall; I never did that but you can find info in this page at section 4.2 (sorry, no direct link). Notice however that that code is referring to a quite old kernel (now Linux kernel has uts
namespaces, whatever they mean) so you will need to change it probably a lot.
Solution 5
scripts/mkcompile_h
In v4.19, this is the file that generates include/generated/compile.h
, and contains several interesting parts of /proc/version
: https://github.com/torvalds/linux/blob/v4.19/scripts/mkcompile_h
-
the
#<version>
part comes from the.version
file on the build tree, which gets incremented whenever link happens (requires file / config changes) byscripts/link-vmlinux.sh
.It can be overridden by the
KBUILD_BUILD_VERSION
environment variable:if [ -z "$KBUILD_BUILD_VERSION" ]; then VERSION=$(cat .version 2>/dev/null || echo 1) else VERSION=$KBUILD_BUILD_VERSION fi
-
the date is just a raw
date
call:if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then TIMESTAMP=`date` else TIMESTAMP=$KBUILD_BUILD_TIMESTAMP fi
and similarly the username comes from
whoami
(KBUILD_BUILD_USER
) and hostname fromhostname
(KBUILD_BUILD_HOST
) The compiler version comes from
gcc -v
, and cannot be controlled it seems.
Here is a how to change stuff version of the question: https://stackoverflow.com/questions/23424174/how-to-customize-or-remove-extra-linux-kernel-version-details-shown-at-boot
Related videos on Youtube
user237251
Updated on September 18, 2022Comments
-
user237251 over 1 year
Where does uname really get its information from?
I figure this is something that should be straightforward. Unfortunately, I can't find any header containing just that information.
Say someone wanted to change the basic output of
uname
/uname -s
fromLinux
to something else (essentially, renaming the kernel).How would he/she go about doing that the proper way (that is, changing the source)?
-
Graeme almost 10 yearsIf you do
strace uname
, it will confirm that theuname
system call is used. -
user237251 almost 10 yearsThanks, everyone. I already knew it had something to do with uname. However, what I can't fathom is how and where inside the source the string "Linux" is defined. All I know is where I can find that information during runtime (it's contained inside /proc/sys/kernel/ostype). Finding out how exactly the kernel itself knows it's proper name would be one of the more interesting things, I'd say.
-
Scott - Слава Україні almost 10 yearsThe
domainname
field is set by thedomainname
command, using thesetdomainname
system call. Similarly, thenodename
field is set by thehostname
command, using thesethostname
system call. (Thenodename
/hostname
value may be stored in/etc/nodename
.) -
goldilocks almost 10 years@Gilles: What's irrelevent? If the answer is "provided by other posters here: it's hard-coded into the kernel..." note I've said the exact same thing: "This comes directly from the running kernel. I would assume all of the information is hard-coded into it...since it is open source, you could change the source code and recompile the kernel to use whatever sysname you want. It is not a config option.
-
Gilles 'SO- stop being evil' almost 10 yearsSome fields there (
nodename
, obviously, and alsomachine
) can be changed at runtime, on a per-process basis. The assumption that your conclusion rests on is wrong. It happens to be true forsysname
, but you need to dig deeper to find this out. -
goldilocks almost 10 years@Gilles O_O? The assumption is obviously correct, as the other answers bare out: it is a hard coded define which could be altered via make or editing the source itself.
-
goldilocks almost 10 years@Gilles : Because the question was about sysname, and I felt safe about that. It says
Linux
because that's what it is, why would it say anything else? +1 to the other answers that confirmed this (I would have done so if prodded by the OP; "it's hard-coded" seems generally sufficient). -
Gilles 'SO- stop being evil' almost 10 years@goldilocks Why would
machine
ever change? It might not be hardcoded into the kernel because it might adapt to the hardware, but surely then it would be set at boot time and wouldn't change after that. But no: it can be set per process (e.g. to reporti686
to 32-bit processed on x86_64). By the way,release
can also be customized per process to some extent (trysetarch i686 --uname-2.6 uname -a
). -
Alen Milakovic almost 10 yearsThis is generally a good and complete answer, but it may be worth while answering the poster's question directl. I believe this would amount to - change the relevant entry in the relevant file and recompile. You wrote "or as a #define in makefiles". Can you elaborate?
-
user237251 almost 10 years@JAB Way too many. Fortunately, someone on kernelnewbies.org helped me solve the "mystery". Linux gets its sys name from /include/Linux/uts.h. See here: lxr.free-electrons.com/source/include/linux/uts.h?v=3.10
-
invot over 7 years+1 for
unshare
. Somehow I managed to miss this command until today. Thanks! -
Ciro Santilli Путлер Капут 六四事 over 5 yearsAnd
include/generated/compile.h
is generated byscripts/mkcompile_h
: unix.stackexchange.com/a/485962/32558