
Linux System Call 101
A system call is a way for a program to request a service from the operating system. It is a low-level interface to the kernel, the core of the operating system. In Linux, system calls are used to perform various operations such as process creation, file management, and inter-process communication.
Here is a basic tutorial on system calls in Linux:
Understanding system calls: A system call is a function provided by the operating system that a process can use to request a service. When a program makes a system call, it is executed in the context of the operating system’s kernel, which has access to hardware and other system resources.
List of common system calls: Linux provides a wide range of system calls that can be used for various purposes. Some of the most common system calls are:
open: Used to open a file or device read: Used to read data from a file or device write: Used to write data to a file or device close: Used to close a file or device fork: Used to create a new process execve: Used to execute a new program in the current process waitpid: Used to wait for a child process to terminate exit: Used to exit the current process kill: Used to send a signal to a process Making system calls: To make a system call in Linux, a program must use the syscall function or a wrapper function provided by the C library. The syscall function takes the number of the system call to be executed as its first argument, followed by any arguments required by the system call.
Here is an example of making a system call to open a file:
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
int main() {
int fd;
fd = syscall(SYS_open, "/tmp/test.txt", O_RDONLY);
if (fd == -1) {
perror("open");
} else {
close(fd);
}
return 0;
}
In this example, the syscall function is used to make the open system call. The first argument to syscall is SYS_open, which is a constant that represents the number of the open system call. The next two arguments are the file to be opened (/tmp/test.txt) and the mode in which it should be opened (O_RDONLY). If the call is successful, the open system call returns a file descriptor, which is stored in the fd variable.
Error handling: When a system call fails, it returns a negative value, and the error code is stored in the errno global variable. The error code can be used to determine the cause of the failure. The perror function can be used to print a descriptive error message for the error code stored in errno.
Wrapper functions: The C library provides wrapper functions for many system calls, which make it easier to use the system calls. For example, instead of using the syscall function to make the open system call, you can use the open function provided by the C library. The wrapper functions often provide a more convenient interface to the system calls, and handle error
Examples
CURL (short for “Client for URLs”) is a command-line tool that is used to transfer data from a server to a client using a variety of protocols, including HTTP, FTP, and SMTP. The tool works by making a system call to the underlying operating system to initiate a network connection and retrieve data.
In Linux, the system calls used by CURL are primarily socket-related system calls such as socket, connect, send, and recv. These system calls are used to establish a network connection and transmit data to and from the server.
Here’s a high-level overview of the steps involved in a CURL request:
- The CURL command is executed on the client.
- The socket system call is used to create a socket, which acts as a communication endpoint for the network connection.
- The connect system call is used to establish a connection to the server.
- The send system call is used to transmit the data request to the server.
- The recv system call is used to receive the data response from the server.
- The response data is processed and displayed on the client.
In addition to these socket-related system calls, CURL also uses other system calls such as gethostbyname to resolve host names to IP addresses, and close to close the socket and release resources.
Overall, CURL provides a convenient and efficient way to interact with a variety of protocols, and the underlying system calls are responsible for the low-level communication with the server.
Tracing
eBPF (extended Berkeley Packet Filter) is a powerful and flexible tracing tool that allows you to monitor and manipulate the behavior of the Linux kernel in real-time. It allows you to run custom programs, called eBPF programs, in the kernel that can trace system calls, network events, or other low-level interactions between the kernel and user space.
eBPF tracing is a process of using eBPF programs to collect data about the behavior of a Linux system. The data collected by these programs can be used to monitor the performance of the system, identify performance bottlenecks, and diagnose problems.
The eBPF tracing tool works by attaching eBPF programs to specific kernel functions, system calls, or other events. When these events occur, the eBPF program is executed and can collect data about the event. The data can then be processed and analyzed to gain insight into the behavior of the system.
One of the key benefits of eBPF tracing is its efficiency. eBPF programs run in the kernel, which allows them to collect data with low overhead and minimal impact on performance. Additionally, eBPF programs are written in a high-level language, which makes it easier to write and maintain complex tracing programs.
There are a number of popular tools and frameworks that utilize eBPF tracing, including BCC (BPF Compiler Collection), tracefs, and perf. These tools provide an interface for writing eBPF programs and analyzing the data they collect.
Overall, eBPF tracing is a powerful tool for diagnosing and optimizing the performance of Linux systems. Its efficiency, flexibility, and ease of use make it a valuable tool for a wide range of use cases.