Fork

Given the following source code:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[]) {

    printf("Staring program...\n");
    int pid = fork();
    if (pid == -1) {
        printf("Error while creating child process using fork: %s", strerror(errno));
        return EXIT_FAILURE;
    }

    if (pid > 0) {
        printf("Hello World from parent process. Parent PID: [%d] Process PID: [%d]  Returned PID: [%d]\n", 
                getppid(), getpid(), pid);
        sleep(2);
        printf("Goodbye from parent process. Parent PID: [%d] Process PID: [%d]  Returned PID: [%d]\n", 
                getppid(), getpid(), pid);
    }

    if (pid == 0) {
        printf("Hello World from child process. Parent PID: [%d] Process PID: [%d]\n", getppid(), getpid());
        printf("Goodbye from child process. Parent PID: [%d] Process PID: [%d]\n", getppid(), getpid());
    }

    printf("Bye from process id [%d]\n", getpid());
    return EXIT_SUCCESS;
}

First steps with forks

  1. When is the child process created ?
  2. Is a new process descriptor created ?
  3. How the child process can be identified from the parent process ?

Create a grand child

  1. Modify the source code to create a new process from the current child process.
  2. Make the new process display a new message.

Parent process management

What is the purpose of the sleep(2) ? Modify the program have the following termination sequence:

  1. The parent process ends first.
  2. Then the child process ends.
  3. Then the grand child process ends.

What is happening ?

Execve

Execve basic execution

Write the following program source code inside two separated files.

Main program

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("Trying to run execve system call...");
    //remplacez ci-dessous "/home/jean" par le chemin du fichier executable.

    char *args[] = {
        "Execve ran program",
        "My Name",
        NULL
    };

    if (execve("<REPLACE_BY_THE_PATH_TO_THE_EXECUTED_PROGRAM>", args, NULL) == -1) {
       perror("Error returned by execve: ");
    } else {
       printf("Error in system call");
    }
    return EXIT_SUCCESS;
}

Executed program

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    printf("I am ran by an execve system call.\nProgram: %s\nWell done %s!\n", argv[0], argc > 1 ? argv[1] : "dear");
    return EXIT_SUCCESS;
}
  1. Compile the executed program using gcc (gcc executed.c -o executed-program).
  2. Compile the main program using gcc.
  3. Execute the main program and describe what is happening.
    1. What is the executed program name argv[0] when executed by execve ?
    2. Execute the executed program inside a bash prompt and compare the program name with the previously obtained value.
  4. Modify the main program source code to launch the execve system call inside a fork.
  5. Modify the main program source code again to add an infinite loop after the execve system call. Describe what is happening.

File descriptor duplication

Given the following source code:

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

int main(int argc, char *argv[]) {

    int text_file_descriptor = open("text.txt", O_RDONLY);
    if (text_file_descriptor == -1) {
        perror("Unable to open text.txt file: ");
        return EXIT_FAILURE;
    }
    printf("File is opened\n");

    // Closing STDIN
    close(STDIN_FILENO);

    int val = dup(text_file_descriptor);
    if (val == -1) {
        fprintf(stderr, "Unable to execute file descriptor %d duplication: %s \n", val, strerror(errno));
        close(text_file_descriptor); // Don't bother of the return code, just attempt to clean.
        return EXIT_FAILURE;
    }
    printf("Duplication of STDIN is made\n");

    char tab[200];
    fgets(tab, sizeof(tab) / sizeof(char), stdin);
    printf("Read data from STDIN: %s\n", tab);

    if (close(text_file_descriptor)) {
        perror("Unable to close text.txt:") ;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

  1. Compile the source code and create a file named "text.txt" next to the binary. Explain what the source code is doing.
  2. What’s the result of close(0) ?
  3. Modify the source code to redirect the standard output (1) to a file named output.txt. What is displayed when executing program ? Explain.

Wait system call

Using man pages of the wait system call write a program that:

  1. Create 3 child processes
  2. Each child process waits for a different time then exits returning the time spent sleeping.
  3. Writes to STDOUT when a child ends a message like "Process XXX ended with return code X."
  4. Writes to STDOUT when all child are ended a message like "All child ended".

Forked processes will sleep for X seconds (different for each child) then return the time spent sleeping.