Where is "uname" pulling information from?

18,338

Solution 1

uname uses the system call uname(2) to get the kernel related information it shows.

The synopsis is:

#include <sys/utsname.h>
int uname(struct utsname *buf);

where uname(2) returns information in the structure pointed to by buf. Also you can read the header file utsname.h from /usr/include/"$(arch)"-linux-gnu/sys/utsname.h to dig deeper.

Have a look at man 2 uname to get more idea about this.

Solution 2

The program strace allows us to view the system calls an application may make. With uname -a it's apparent that the only open calls go to system libraries, so technically there is no file on the filesystem that the uname opens for reading. Rather it makes system calls using the C libraries.

As heemayl properly pointed out there exists sys call to retrieving the information stored in the uname structure. It's man page, suggests the following:

This is a system call, and the operating system presumably knows its name, release and version . . . . . . Part of the utsname information is also accessible via /proc/sys/ker‐ nel/{ostype, hostname, osrelease, version, domainname}.

Part of the utsname information is also accessible via /proc/sys/ker‐ nel/{ostype, hostname, osrelease, version, domainname}.

/proc filesystem however is virtual, meaning it exists only while the OS is running. Thus to some extend it is set within kernel or system libraries.

Finally, reading through the source code of uname.c which can be obtained with apt-get source coreutils , we can see that it indeed uses the utsname.h library(printed with line numbers):

 19 
 20 #include <config.h>
 21 #include <stdio.h>
 22 #include <sys/types.h>
 23 #include <sys/utsname.h>
 24 #include <getopt.h>
 25 

strace output:

skolodya@ubuntu:$ strace uname -a
execve("/bin/uname", ["uname", "-a"], [/* 58 vars */]) = 0
brk(0)                                  = 0x1478000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efee6935000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=137226, ...}) = 0
mmap(NULL, 137226, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7efee6913000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0
mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7efee6350000
mprotect(0x7efee650b000, 2093056, PROT_NONE) = 0
mmap(0x7efee670a000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7efee670a000
mmap(0x7efee6710000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7efee6710000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efee6912000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efee6910000
arch_prctl(ARCH_SET_FS, 0x7efee6910740) = 0
mprotect(0x7efee670a000, 16384, PROT_READ) = 0
mprotect(0x606000, 4096, PROT_READ)     = 0
mprotect(0x7efee6937000, 4096, PROT_READ) = 0
munmap(0x7efee6913000, 137226)          = 0
brk(0)                                  = 0x1478000
brk(0x1499000)                          = 0x1499000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7216688, ...}) = 0
mmap(NULL, 7216688, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7efee5c6e000
close(3)                                = 0
uname({sys="Linux", node="eagle", ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efee6934000
uname({sys="Linux", node="eagle", ...}) = 0
uname({sys="Linux", node="eagle", ...}) = 0
write(1, "Linux eagle 4.1.0-040100rc2-gene"..., 113Linux eagle 4.1.0-040100rc2-generic #201505032335 SMP Mon May 4 03:36:35 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
) = 113
close(1)                                = 0
munmap(0x7efee6934000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Solution 3

Of course heemayl's answer is correct.

Just for fun, here's a working C snippet showcasing the data returned by uname() (a sort of a homemade uname if you want): compile it with gcc uname.c -o uname and run it with ./uname:

#include <stdio.h> // printf()
#include <sys/utsname.h> // uname()

int main() {
        int ret; // stores the return value of uname()
        struct utsname utsname; // stores the data returned by uname()
        struct utsname *utsname_ptr = &utsname; // pointer to the struct holding the data returned by uname()

        ret = uname(utsname_ptr); // calls uname() on utsname_ptr and stores its return value in ret

        /* prints the fields of utsname */

        printf("%s\n", utsname.sysname);
        printf("%s\n", utsname.nodename);
        printf("%s\n", utsname.release);
        printf("%s\n", utsname.version);
        printf("%s\n", utsname.machine);

        /* returns the return value of uname() */

        return(ret);
}
% ./uname 
Linux
user-X550CL
4.2.0-25-generic
#30-Ubuntu SMP Mon Jan 18 12:31:50 UTC 2016
x86_64

Solution 4

As an addition to heemayl's answer, you can get some information like in the uname command from /proc/version.

Share:
18,338

Related videos on Youtube

Roy Hernandez
Author by

Roy Hernandez

Updated on September 18, 2022

Comments

  • Roy Hernandez
    Roy Hernandez almost 2 years

    Where is uname -i pulling the information from?

    Do the details exist in /etc/?

    Do the details exist in /proc/?

    If so, which file is it referencing to output those details?

  • Roy Hernandez
    Roy Hernandez over 8 years
    when I run "uname -i", the output is "x86_64". When I cross reference "/usr/include/x86_64-linux-gnu/sys/utsname.h", I don't see anything that references "x86_64". I referenced the "man 2 uname" and it states that part of utsname information is referenced via "/proc/sys/kernel/{ostype}, {hostname}, {osrelease}, {version} and {domainname}" the problem is that none of those files reference anything stating "x86_64". Any other recommendations?
  • Roy Hernandez
    Roy Hernandez over 8 years
    when I run "uname -i", the output is "x86_64". When I cross reference "/usr/include/x86_64-linux-gnu/sys/utsname.h", I don't see anything that references "x86_64". I referenced the "man 2 uname" and it states that part of utsname information is referenced via "/proc/sys/kernel/{ostype}, {hostname}, {osrelease}, {version} and {domainname}" the problem is that none of those files reference anything stating "x86_64". Any other recommendations?
  • Roy Hernandez
    Roy Hernandez over 8 years
    /proc/version contains "Linux version 3.19.0-47-generic (buildd@lgw01-19) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #53~14.04.1-Ubuntu SMP Mon Jan 18 16:09:14 UTC 2016" and "uname -i" output is "x86_64".
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy over 8 years
    @RoyHernandez In C it's possible to determine architecture of a CPU based on the size that integer takes , for instance - refer here. So the uname.c doesn't necessarily need to use a library for that - we can look at the source code, of course, to be sure.
  • heemayl
    heemayl over 8 years
    @RoyHernandez Whats the output of locate --regex '^/usr/include/.*/sys/utsname.h$'?
  • Roy Hernandez
    Roy Hernandez over 8 years
    The output is: "/usr/include/x86_64-linux-gnu/sys/utsname.h "
  • heemayl
    heemayl over 8 years
    @RoyHernandez This tells that the file does exist and you were doing something wrong..
  • Roy Hernandez
    Roy Hernandez over 8 years
    machine.h seems to be peppered throughout the system. Which machine.h file does it rely on?
  • Roy Hernandez
    Roy Hernandez over 8 years
    where is the printf("%\n", utsname.machine); pulling it's information from?
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy over 8 years
    @RoyHernandez all the listed machine.h on my system seem to be in the /usr/src/linux-headers-3.19.0-33 directory. It's very likely that it uses the library provided by the currently running kernel
  • Roy Hernandez
    Roy Hernandez over 8 years
    When I run a uname -i the output is x86_64. When I run locate --regex '^/usr/include/.*/sys/utsname.h$' the output returns /usr/include/x86_64-linux-gnu/sys/utsname.h
  • Roy Hernandez
    Roy Hernandez over 8 years
    I am not sure... I don't see a machine.h on my computer within the /usr/src/linux-headers-3.19.0-33 directory. I am not sure how to cross reference the output of uname -i.
  • heemayl
    heemayl over 8 years
    @RoyHernandez so, i don't get it..whats wrong with /usr/include/"$(uname -i)"-linux-gnu/sys/utsname.h ?
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy over 8 years
    How about this ? find /usr/src/linux-headers-$(uname -r)/include/ -name "machine.h"
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy over 8 years
    Let me actually read the source of uname.c a bit more, and I'll get back to you later once i figure this out.
  • Roy Hernandez
    Roy Hernandez over 8 years
    find /usr/src/linux-headers-$(uname -r)/include/ -name "machine.h" output is /usr/src/linux-headers-3.19.0-47-generic/include/config/stop‌​/machine.h
  • Roy Hernandez
    Roy Hernandez over 8 years
    I am not sure. I am just trying to figure out where uname -i is gathering it's output and it seems to be verify difficult.
  • kos
    kos over 8 years
    Then the call to uname() has the effect of populating the struct utsname, which at the time of the printf() call contains the various values inside the various fields. Unluckily if you are not familiar with C this is probably not going to be easy to grasped in detail, but the point is that uname() populates a data structure built on purpose, whose fields are later printed via printf().