How a linux command uses C system call defined in header files?
In this post, we will check how a linux command executes on the system.
We will learn how a linux command is manipulated by the bash and how it uses the system calls defined in C header files.
For this lets take example of uname command.
1. Uname command description
uname prints information about our software and hardware. A 64-bit machine could be running a 32-bit Linux distribution also.
[root@ngelinux ~]# uname -a Linux ngelinux 2.6.32-696.el6.i686 #1 SMP Tue Mar 21 18:53:30 UTC 2017 i686 i686 i386 GNU/Linux [root@ngelinux ~]#
uname -a prints this information (in order): kernel-name, nodename, kernel-release, kernel-version, machine, processor, hardware-platform, operating-system. If you see 64 bit hardware and i686 kernel, then you have installed a 32-bits Linux kernel.
2. Trace uname command
uname is a system call and we can use starce command to trace the command execution.
The tracing is helpful to understand what all files read by command, however we can’t track what all system calls defined in programming uname.
For this you need to read about linux programming.
[root@ngelinux ~]# strace -v /bin/uname -a execve("/bin/uname", ["/bin/uname", "-a"], ["HOSTNAME=ngelinux", "SELINUX_ROLE_REQUESTED=", "TERM=xterm", "SHELL=/bin/bash", "HISTSIZE=1000", "SSH_CLIENT=192.168.52.1 64654 22", "SELINUX_USE_CURRENT_RANGE=", "SSH_TTY=/dev/pts/1", "USER=root", "LS_COLORS=rs=0:di=01;34:ln=01;36"..., "LIBGL_DRIVERS_PATH=/usr/lib/dri", "MAIL=/var/spool/mail/root", "PATH=/usr/local/sbin:/usr/local/"..., "PWD=/root", "LANG=en_US.UTF-8", "SELINUX_LEVEL_REQUESTED=", "SSH_ASKPASS=/usr/libexec/openssh"..., "HISTCONTROL=ignoredups", "SHLVL=1", "HOME=/root", "LOGNAME=root", "CVS_RSH=ssh", "SSH_CONNECTION=192.168.52.1 6465"..., "LESSOPEN=||/usr/bin/lesspipe.sh "..., "G_BROKEN_FILENAMES=1", "_=/usr/bin/strace"]) = 0 brk(0) = 0x892e000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e7000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_dev=makedev(8, 1), st_ino=663400, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=136, st_size=66865, st_atime=2018/01/14-23:12:07, st_mtime=2018/01/13-23:12:04, st_ctime=2018/01/13-23:12:04}) = 0 mmap2(NULL, 66865, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77d6000 close(3) = 0 open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200N\215\0004\0\0\0"..., 512) = 512 fstat64(3, {st_dev=makedev(8, 1), st_ino=920280, st_mode=S_IFREG|0755, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=3744, st_size=1912920, st_atime=2018/01/14-20:48:25, st_mtime=2017/03/21-10:49:29, st_ctime=2017/12/18-05:09:28}) = 0 mmap2(0x8be000, 1665484, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x8be000 mmap2(0xa4f000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000) = 0xa4f000 mmap2(0xa52000, 10700, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xa52000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77d5000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb77d56c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 access("/etc/sysconfig/32bit_ssse3_memcpy_via_32bit_ssse3_memmove", F_OK) = -1 ENOENT (No such file or directory) mprotect(0xa4f000, 8192, PROT_READ) = 0 mprotect(0x8b6000, 4096, PROT_READ) = 0 munmap(0xb77d6000, 66865) = 0 brk(0) = 0x892e000 brk(0x894f000) = 0x894f000 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3 fstat64(3, {st_dev=makedev(8, 1), st_ino=142541, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=193704, st_size=99174416, st_atime=2018/01/14-20:50:01, st_mtime=2017/11/14-08:10:11, st_ctime=2017/12/18-05:04:57}) = 0 mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb75d5000 close(3) = 0 uname({sysname="Linux", nodename="ngelinux", release="2.6.32-696.el6.i686", version="#1 SMP Tue Mar 21 18:53:30 UTC 2017", machine="i686", domainname="(none)"}) = 0 fstat64(1, {st_dev=makedev(0, 11), st_ino=4, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=0, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 1), st_atime=2018/02/17-03:33:50, st_mtime=2018/02/17-03:33:50, st_ctime=2018/02/16-22:03:15}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e6000 uname({sysname="Linux", nodename="ngelinux", release="2.6.32-696.el6.i686", version="#1 SMP Tue Mar 21 18:53:30 UTC 2017", machine="i686", domainname="(none)"}) = 0 uname({sysname="Linux", nodename="ngelinux", release="2.6.32-696.el6.i686", version="#1 SMP Tue Mar 21 18:53:30 UTC 2017", machine="i686", domainname="(none)"}) = 0 write(1, "Linux ngelinux 2.6.32-696.el6.i6"..., 96Linux ngelinux 2.6.32-696.el6.i686 #1 SMP Tue Mar 21 18:53:30 UTC 2017 i686 i686 i386 GNU/Linux ) = 96 close(1) = 0 munmap(0xb77e6000, 4096) = 0 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++ [root@ngelinux ~]#
3. uname system call
We have got below program from web page: https://askubuntu.com/questions/724415/where-is-uname-pulling-information-from and its copyright to specific author and not NGEL.
#include < stdio.h > // Contains printf() command. #include < sys/utsname.h > // It is the library containing the uname system call. 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); }
From the above program, it is clear that uname command uses the system calls as defined in utsname.h header file.
Similar to uname command, every command uses C libraries/header files, and the calls defined in them.