Linux Kernel

Linux Kernel API

We will go through the Linux application programming interface, the API. Linux kernel provides the system calls which can be used to get the task done through kernel. Let us discuss the few, widely used system calls of Linux.

Description:

Linux kernel provides the set or list of functions which can be used by the user space programs to utilize the Linux kernel services.

The block diagram looks like the following:

Some of the few widely used system calls are open, close, read, and write. These are basic system calls provided by Linux kernel. Every task is done through file in Linux. So, the basic operations on any file can be done through open, close, read, and write.

Let us take a real example where we want to print the “hello world” on serial console. To achieve this task through system calls, we need to open the device file for console in /dev. Once we locate the device file for console or uart, we can use the open system call to open the device.

Here is the syntax of the open system call:

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

From this syntax, the first argument is the file path which we want to open. In our case, it is the device file which we located as a console device. In the next argument, the flags provide the user some flexibility to play with the file. Few example of the flags are O_CREAT, O_APPEND, etc. These flags have specific meanings and purpose and the discussion is out of the scope of this discussion. For more details on the flags and parameters, please refer the kernel man pages.

Once the file is open successfully, we need to use the write system call to send the “hello world” to the console device. The prototype of the write system call is as follows:

ssize_t write(int fd, const void *buf, size_t count);

The first parameter of the write system call is the fd which is the file descripter. The “fd” is given to us by the open system call. After opening the file successfully, we should get the file descriptor. This fd is used further to write the data.

The second parameter is the buffer address for the data to be sent to the console device. In our case, the test data is “hello world”.

The last parameter is the total number of bytes that the user wants to write to the console device. In our case, the number of bytes is the size of “hello world”. We can either use the sizeof operator or the strlen function to get the number of bytes. We should be careful while using the strlen. This function ignores the string terminator character like “\0”. So, while reading the string, we have to ensure that the null character is handled properly. Otherwise, we will end up with the segmentation fault.

Now, let us implement the code part of this example. First, we need to locate the serial console or uart device. In the machine, what we use has the serial tty device as /dev/pts/0. So, as discussed, we first need to open this file. We must also include the harder file which provides the declaration of open system call.

Our code for opening the device file looks like the following:

#include <fcntl.h>

fd = open(/dev/pts/0, O_WRONLY);

Next, when we want to call the write system call, we use the fd provided by the open. Our call to write function looks like the following:

#include <unistd.h>

char *data = “hello world”;

write(fd, data, strlen(data)+1);

The previous code snippet writes the “hello world” to the serial console that we located and want to write.

Let us put all the pieces together:

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int main()
{
    int fd; int rc;
    char *data = “hello world”;
fd = open(/dev/pts/0, O_WRONLY);
    if(fd<0)
    {
printf(“Error opening file:%d”,fd);
        exit(-1);
    }
rc = write(fd, data, strlen(data)+1);
    if(rc<0)
    {
printf(“Error writing file:%d”,rc);
        exit(-1);
    }
    close(fd);  // file operation is done, close the file.
    return 0;
}

Compiling of the previous program is the same as compiling the other C programs like the following:

gcc test_write.c -o test_write.

The test_write.c is the file name to our C code.

After the compilation, we get the executable with the test_write name.

Refer to the following snapshot:

After running the compiled and generated binary, we have the following output.

Our program output is highlighted in bold letters. The following is the snapshot for reference:

So far, we have seen an example where we use the Linux API to display the test string to the console. This is the simple example. There are many other offerings that are provided by the system call. Few of the system calls which are provided by Linux are as follows:

  • read: Reading from the file.
  • write: Writing to the file.
  • open: Opening the file.
  • close: Closing the file.
  • poll: Polling the device for the change in state.
  • lseek: Seeking at a particular offset in the file.
  • mmap: Mapping the virtual memory to the physical memory.
  • brk: Change the segment size.
  • ioctl: Control devices.
  • access: Access to get the permissions of file.
  • pipe: Refers to the pipe creation.

and many more.

This is the huge list of functions provided by Linux kernel. We have seen and discussed very few. Refer to the kernel source for the complete list of system calls that is provided by kernel.

Conclusion

We discussed about the system calls which is a way to ask the kernel to perform the tasks for the user space programs. Without the system call, it will not be possible for the user space programs to get the task done by the kernel. We took a simple task or example of writing the test data, “hello world”, to the serial device. We employed the open, write, and close API’s of the kernel to complete the task in hand. One most important thing is to check the system call return value. Kernel provides proper return values to explain the reason in case of failure of function. The user can get the idea on the failure reason by seeing the return values from the system call. Return values have some specific meaning and are well-captured in the kernel documentation.

About the author

Sushil Rathore

Sushil Rathore is having hands-on experience in Linux Platform SW. He's an expert of Linux on ARM/X86 Boards. He has very good understanding on Bootloaders and other platform softwares. He has good industrial experience and have worked in reputed Organizations. Currently he is associated with a reputed firm in the networking domain.