Using Linux Syscalls in C Programming

This topic was published by and viewed 3458 times since "". The last page revision was "".

Viewing 1 post (of 1 total)
  • Author
    Posts

  • DevynCJohnson
    Keymaster
    • Topics - 437
    • @devyncjohnson

    The Linux kernel has many system calls (syscalls) that perform low-level tasks. These system calls can be used as functions when writing programs that perform a low-level task or retrieve information from the kernel and other important processes. It may help some Linux users to understand how to implement syscalls in their programming.

    Brief Intro to Syscalls

    A system call is a special function/command that a program uses to communicate with the kernel of the operating system. The Linux kernel has a variety of system calls that it recognizes. There are about six kinds of system calls (depending on how you want to classify them). These six are process control, information maintenance, communication, file management, memory management, and device management. "Information maintenance" is referring to system time, attributes of files and devices, and many other sets of information. "Communication" refers to networking, data transfer, attachment/detachment of remote devices.

    When an application is compiled on Linux, it gets the code for the standard system calls from the GNU C Library, which is also called "glibc". This is the library used for applications that run on systems using the Linux kernel, Hurd kernel, or GNU userland. Some derivatives of glibc are used in applications running on other kernels. One reason why applications compiled for one operating system do not work on another is because the application uses different system calls.

    More can be learned about syscalls at https://dcjtech.info/topic/linux-kernel-system-calls/

    Programming with Syscalls

    When writing a program in C or some other programming language, it is important to know that programs should not use a real system call directly. Rather, system calls should use a wrapper, such as libc (glibc). When using wrappers, the system call commands will use the same parameters as the real kernel system calls.

    In C-programming, the library that provides access to syscalls is "<sys/syscall.h>" which is obtain from the "Kernel headers" package. This C library provides wrappers for using the syscall. Once the program is compiled and working, it does not initiate the syscalls directly. Instead, the program uses functions from the libc library.

    When programming syscalls in applications, it is best to view the man-pages to know the parameters and data-types associated with the syscall. To lookup a system call in the man-pages via command-line, type "man 2 SYSCALL" where "SYSCALL" is the name of the system call that will be used. The "2" indicates that the syscall portion of the man-pages will be searched for the desired syscall. Once the man-page is found, information about the syscalls parameters, parameter data-types, data-type of output, and programming notes will be seen and should be read carefully. If the man-page does not provide enough information (or none at all), then check the Internet for the needed information.

    Example Syscall Usage

    The best way to learn how to use a syscall is by seeing a simple yet useful and real example. I made a small command-line program using the C programming language. This program returns the Session ID (SID) of the specified Process ID (PID). The Session ID is retrieved by the "getsid()" syscall.

    NOTE: The below code will only work on Linux. Windows and many other operating systems do not have the "getsid()" syscall.

    #define _GNU_SOURCE
    
    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <unistd.h>
    
    #include <sys/syscall.h>
    
    #include <sys/types.h>
    
    //getsid() - returns the Session ID
    
    int main(int argc, char *argv[]) {
    
        int pid, sid;
    
        if (argc > 2) {
    
            printf("Expected one or no parameters, but was given %d\n", argc - 1);
    
            return 1;
    
        } else if (argc == 1) {
    
            pid = 0;
    
        } else {
    
            pid = atoi(argv[1]);
    
        }
    
        pid_t getsid(pid_t pid);
    
        sid = getsid(pid);
    
        printf("%d\n", sid);
    
        return 0;
    
    }

    The compiled executable is used in a command-line and uses a PID as an argument (getsid PID). The command then returns the Session ID of the specified PID. If no PID is specified, then a PID of "0" is assumed.

    NOTE: The official download page for the "getsid" command-line utility is https://dcjtech.info/topic/getsid-get-session-id-utility/. That page also includes compilation and installation instructions.

    The "<sys/syscall.h>", "<sys/types.h>", and "<unistd.h>" are needed to use the "getsid" syscall. Some system calls (like "statvfs") need different libraries, so be sure to research the needed libraries for the desired syscall. The "pid_t" data-type is a signed integer that is used for Process IDs, Session IDs, Parent Process Ids, and possibly some other IDs. Integers (int) and "pid_t" data can be type-casted between each other easily.

    To use "getsid", the syscall must be initialized and its return value and parameters must have their data-types properly declared (pid_t getsid(pid_t pid);). After the syscall is initialized, it can be used as a function ("sid = getsid(pid);"). In that line of code, the Session ID of the specified PID (pid) is returned by the syscall (technically a syscall wrapper) and stored in the variable "sid".

    getsid-Usage getsid-Usage

    As mentioned before, some syscalls may use different libraries and the syscall itself may need to be initialized in some special way. For instance, to use the "statvfs" system call, the library "<sys/statvfs.h>" is needed, but not "<sys/syscall.h>", "<sys/types.h>", or "<unistd.h>". In addition, the buffer used by statvfs must be declared ("struct statvfs buf;"). When statvfs is executed as a function/command, the data is stored in "buf". When running "statvfs", the output is the return-status code. For example, to use "statvfs", the initialization code is "int statvfs(const char *path, struct statvfs *buf);" and "statvfs" is executed as "ret = statvfs(path,&buf);". To get the filesystem data retrieved by statvfs, access the "buf" variable in a form like "buf.f_bsize" to get the block size. To output such a value in a command-line, the printf command could be used - printf("Block Size (bytes): %ld\n", buf.f_bsize);

    Obviously, when using syscalls, it is very important to view documentation about the desired syscall and understand the data-types and required libraries.

    Further Reading

    Attachments:
    1. getsid-Usage
Viewing 1 post (of 1 total)