System Call =========== Examples -------- fork - Call the fork syscall - Parent waits until child exits - Child sleeps 2 seconds, afterwards, it exits .. code-block:: c #include #include #include #include #include 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. .. code-block:: c #include #include #include #include #include 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. .. code-block:: c #include #include #include #include #include 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 .. code-block:: c #include #include #include #include #include #include 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 .. code-block:: c #include #include #include #include #include #include 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. .. figure:: ../images/tutorial3/libcall.png To confirm the issue, let's use the following program that reads data from procfs. .. code-block:: c #include 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.