System Call

Examples

fork

  • Call the fork syscall

  • Parent waits until child exits

  • Child sleeps 2 seconds, afterwards, it exits

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <sys/wait.h>

int main(void)
{
  pid_t pid;

  pid = fork();
  if (pid < 0) {
    perror("fork failed");
    exit(1);
  } else if (pid == 0) {
    printf("I am child, sleep 2 seconds\n");
    sleep(2);
    printf("I am child, 2 seconds have passed, now I exit\n");
  } else {
    printf("I am parent, I wait until child exits\n");
    wait(NULL);
    printf("I am parent, OK, now child has exited, I also exit\n");
  }

  return 0;
}

fork + execvp

  • Call the fork syscall

  • Parent waits until child exits

  • Child calls the execvp syscall to execute the sleep UNIX command.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <sys/wait.h>

int main(void)
{
  pid_t pid;

  pid = fork();
  if (pid < 0) {
    perror("fork failed");
    exit(1);
  } else if (pid == 0) {
    char *argv[3];
    argv[0] = "sleep";
    argv[1] = "2";
    argv[2] = NULL;
    printf("I am child, sleep 2 seconds\n");
    if (execvp(argv[0], argv) < 0) {
      perror("exec failed");
      exit(1);
    }
  } else {
    printf("I am parent, I wait until child exits\n");
    wait(NULL);
    printf("I am parent, OK, now child has exited, I also exit\n");
  }

  return 0;
}

fork + chdir + execvp

  • Call the fork syscall

  • Parent waits until child exits

  • Child moves to a directory /home.

  • Child calls the execvp syscall to execute the pwd UNIX command to show the current directory.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <sys/wait.h>

int main(void)
{
  pid_t pid;

  pid = fork();
  if (pid < 0) {
    perror("fork failed");
    exit(1);
  } else if (pid == 0) {
    char *argv[3];
    printf("I am child, I move to /home\n");
    if (chdir("/home") < 0) {
      perror("chdir failed");
      exit(1);
    }
    argv[0] = "pwd";
    argv[1] = NULL;
    printf("I am child, I execute pwd\n");
    if (execvp(argv[0], argv) < 0) {
      perror("exec failed");
      exit(1);
    }
  } else {
    printf("I am parent, I wait until child exits\n");
    wait(NULL);
    printf("I am parent, OK, now child has exited, I also exit\n");
  }

  return 0;
}

open + read + close

  • Open a (special) file “/proc/cpuinfo”

  • Read the content and print out

  • Close the file

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <error.h>

int main(void)
{
  int fd;
  ssize_t len = 0;
  char buf[256];

  fd = open("/proc/cpuinfo", O_RDONLY);
  if (fd < 0) {
    perror("open failed");
    exit(1);
  }

  do {
    memset(buf, 0, sizeof(buf));
    len = read(fd, buf, sizeof(buf)-1);
    if (len < 0) {
      perror("read failed");
      exit(1);
    }
    buf[len] = '\0';
    printf("%s", buf);
  } while (len > 0);

  close(fd);

  return 0;
}

open + write + close

  • Open a file named “./syscall_write_example.txt”

  • Write a string “hello” to the file

  • Close the file

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <error.h>

int main(void)
{
  int fd;
  ssize_t len = 0;

  fd = open("./syscall_write_example.txt", O_WRONLY | O_CREAT, 0644);
  if (fd < 0) {
    perror("open failed");
    exit(1);
  }

  len = write(fd, "hello\n", 6);
  if (len < 0) {
    perror("write failed");
    exit(1);
  }

  close(fd);

  return 0;
}

Differences between system calls and library functions

We can use library functions for reading and writeing files instead of system calls.

The examples of library functions are fputc (write a character) and fgetc (read a character). They are implemented as part of the standard library using system calls. In other words, such library functions are somewhat wrappers of system calls.

../_images/libcall.png

To confirm the issue, let’s use the following program that reads data from procfs.

#include <stdio.h>

int main(void)
{
  FILE *fp;
  fp = fopen("/proc/cpuinfo", "r");
  while (1) {
    char c = fgetc(fp);
    if (c == EOF)
      break;
    printf("%c", c);
  }
  fclose(fp);
  return 0;
}

Please compile the program above and run it with strace which is a command shows which system calls are called while the program is running.:

$ gcc PROGRAM.c
$ strace ./a.out

If you do not have the strace command on your VM, please install it using the following command.:

$ sudo apt install strace

Supposedly, you will find a lot of write and read system calls are called, but you won’t see fgetc. This is because fgetc just calls the read system call internally.