Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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 from Linux to something else (essentially, renaming the kernel).

How would he/she go about doing that the proper way (that is, changing the source)?

share|improve this question

5 Answers 5

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 */

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.

share|improve this answer
The domainname field is set by the domainname command, using the setdomainname system call. Similarly, the nodename field is set by the hostname command, using the sethostname system call. (The nodename / hostname value may be stored in /etc/nodename.) –  Scott Jun 13 '14 at 19:15
This is irrelevant — the question asked where to change this. So yes, the uname command gets its information from a system call. And where does the system call get its information? (Answer, provided by other posters here: it's hard-coded in the kernel at compile time.) –  Gilles Jun 14 '14 at 22:35
@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. –  goldilocks Jun 16 '14 at 12:14
@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 report i686 to 32-bit processed on x86_64). By the way, release can also be customized per process to some extent (try setarch i686 --uname-2.6 uname -a). –  Gilles Jun 16 '14 at 13:20
@Gilles I've edited machine, nodename, and release into the question with a reference to the comments. Again, the question wasn't actually about all those fields. –  goldilocks Jun 16 '14 at 13:30

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,

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

#define UTS_SYSNAME "Linux"

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
# unshare --uts /bin/bash
# echo test > /proc/sys/kernel/hostname 
# hostname
# exit
# hostname
share|improve this answer
This 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? –  Faheem Mitha Jun 16 '14 at 18:12

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 
#define UTS_SYSNAME "Linux"

So, as the kernel documentation states:

The only way to tune these values is to rebuild the kernel :-)

share|improve this answer

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:


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)\";)

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))';)

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

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

PHONY += headerdep
    $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
    $(srctree)/scripts/ -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.

share|improve this answer
Thanks, 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. –  user237251 Jun 13 '14 at 17:48
@user237251 how many instances of the word "Linux" occur in the kernel source in string contexts? If it's not that many, you could just examine the results of a textual search and see where that leads you. –  JAB Jun 13 '14 at 17:55
@JAB Way too many. Fortunately, someone on helped me solve the "mystery". Linux gets its sys name from /include/Linux/uts.h. See here: –  user237251 Jun 17 '14 at 17:14

While I couldn't find anything in the source to indicate this, I believe it uses the uname syscall.

man 2 uname

should tell you more about it. If that's the case it's getting the information directly from the kernel and changing it would probably require recompilation.

You could change the binary for you uname to do whatever you want though, just write over it with w/e program you please. The downside being some scripts rely on that output.

share|improve this answer
If you do strace uname, it will confirm that the uname system call is used. –  Graeme Jun 13 '14 at 14:11

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.