System Calls for File Operations in Unix/Linux

1. Systems Calls

In an operating system, a process runs in two different modes; kernel mode and user mode, denoted by Kmode and Umode for short. While in Umode, a process has very limited privileges. It can not do anything that requires special privileges. Privileged operations must be done in Kmode. System call, or syscall for short, is a mechanism which allows a process to enter Kmode to perform operations not allowed in Umode. Operations such as fork child process, exec to change execution image, even termination must all be done in Kernel. In this chapter, we shall discuss syscalls for file operations in Unix/Linux.

2. System Call Man Pages

In Unix and most versions of Linux, the online manual (man) pages are maintained in the /usr/man/ directory (Goldt et al. 1995; Kerrisk 2010, 2017). In Ubuntu Linux, they are in the /usr/share/man directory. All the syscall man pages are listed in the man2 subdirectory. The sh command man 2 NAME displays the man pages of the syscall NAME. For example,

man 2 stat : display man pages of stat(), fstat() and lstat() syscalls

man 2 open: display man pages of open() syscall

man 2 read: display man pages of read() syscall, etc.

Many syscalls require specific included header files, which are listed in the SYNOPSIS part of the man pages. Without proper header files, the C compiler may generate many warnings due to mismatches in syscall function name types. Some syscalls may also require specific data structures as parameters, which must be present as described in the man pages.

3. System Calls for File Operations

Syscalls must be issued from a program. Their usage is just like ordinary function calls. Each syscall is a library function, which assembles the syscall parameters and ultimately issues a syscall to the OS kernel.

int syscall(int a, int b, int c, int d);

where the first parameter a is the syscall number, and b, c, d are parameters to the corresponding kernel function. In Intel x86 based Linux, syscalls are implemented by the INT 0x80 assembly instruction, which causes the CPU to switch from User mode to Kernel mode. The kernel’s syscall handler routes the call to a corresponding kernel function based on the syscall number. When the process finishes executing the kernel function, it returns to User mode with the desired results. A return value >=0 means SUCCESS, -1 means FAILED. In case of failure, an errno variable (in errno.h) records the error number, which can be mapped to a string describing the error reason. The following example shows how to use some of simple syscalls.

Example C8.1. mkdir, chdir, getcwd, syscalls.

/************ C8.1.c file ************/

#include <stdio.h>

#include <errno.h> int main()

{

char buf[256], *s;

int r;

r = mkdir(“newdir”, 0766); // mkdir syscall

if (r < 0)

printf(“errno=%d : %s\n”, errno, strerror(errno));

r = chdir(“newdir”);        // cd into newdir

s = getcwd(buf, 256);       // get CWD string into buf[ ]

printf(“CWD = %s\n”, s);

}

The program issues a mkdir() syscall to make a new directory. The mkdir() syscall requires a pathname and a permission (0766 in octal). If newdir does not exist, the syscall would succeed with a 0 return value. If we run the program more than once, it should fail on the second or any successive runs with a return value -1 since the directory already exists. In that case, the program would print the message

errno=17 : File exists

In addition to mkdir(), the program also illustrates the usage of chdir() and getcwd() syscalls.

EXERCISE: Modify the C8.1 program to make many directories in one run, e.g.

mymkdir dirl dir2 dir3, … dirn

Hint: write main() as main(int argc, char *argv[ ])

Simple System Calls: The following lists some of the simple syscalls for file operations. The reader is encouraged to write C programs to use and test them.

access : check user permissions for a file.

int access(char *pathname, int mode);

chdir : change directory

int chdir(const char *path);

chmod : change permissions of a file

int chmod(char *path, mode_t mode);

chown : change owner of file

int chown(char *name, int uid, int gid);

chroot : change (logical) root directory to pathname

int chroot(char *pathname);

getcwd : get absolute pathname of CWD

char *getcwd(char *buf, int size);

mkdir : create a directory

int mkdir(char *pathname, mode t mode);

rmdir : remove a directory (must be empty)

int rmdir(char *pathname);

link : hard link new filename to old filename

int link(char *oldpath, char *newpath);

unlink : decrement file’s link count; delete file if link count reaches 0

int unlink(char *pathname);

symlink : create a symbolic link for a file

int symlink(char *oldpath, char *newpath);

rename : change the name of a file

int rename(char *oldpath, char *newpath);

utime : change access and modification times of file

int utime(char *pathname, struct utimebuf *time)

The following syscalls require superuser privilege.

mount : attach a file system to a mounting point directory

int mount(char *specialfile, char *mountDir);

umount : detach a mounted file system

int umount(char *dir);

mknod : make special files

int mknod(char *path, int mode, int device);

Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.

Leave a Reply

Your email address will not be published. Required fields are marked *