BasicOS
Basics
of
Operating
Systems

General information

Protection and system calls

This session is dedicated to the study of protection and system calls in Operating Systems.

You don't need to submit source files or reports for this session.

For this session, you will need to log into a PC running Linux. If you are at Eurecom, simply log on a PC of rooms 52 or 53. If you were to use another PC running GNU/Linux, I cannot guarantee that the lab works in the same way (outputs could be different, manual pages could be different, etc.).

Important: you will create test files, some of which will be large. As your disk quota is limited you will create these files in the /tmp directory which purpose is actually to store temporary files. It can perfectly be that another student works remotely on the same computer as you. To avoid clashes first create a subdirectory with your user name (in the following we represent your user name as USERNAME):

# Do not just copy-paste this: replace USERNAME with your user name
$ mkdir -p /tmp/USERNAME
At the end of the lab please do not forget to delete all temporary files to free disk space in /tmp (but be careful when using rm -rf, if you get it wrong the consequences can be catastrophic; check your typing twice):
$ rm -rf /tmp/USERNAME

Trick. Under GNU/Linux you can easily copy/paste with the mouse: select some text (click and drag, double-click or triple-click), move your cursor to the destination and click with the middle button (or the wheel).

I. Basic

  1. Be sure you have understood all the slides on the Introduction on Operating Systems
  2. How would you define a system call? Once you are happy with your definition, you can check on wikipedia for instance.

II. Services

  1. Type the following command. How do you explain the difference with the write() function of the source code given as example in the slides?
    $ man write
  2. Similarly, try to figure out if the following command are bash commands, syscalls, or C library functions: read, print, printf, malloc, exit, getpid, ps
    (Help me!) Use man -s2 f to know if a function f is a syscall or not

III. Using system calls and data structures

In this exercise you will learn how to compile a C program, how to correct errors and warnings, how to use basic data structures, and finally how to use Linux system calls. You will also discover how to manipulate files from a C program.

  1. In this exercise, you will manipulate files: we read from a text files lines one by one, and we put each line content in a linked list. A linked list is a set of cells, each cell containing a value and a pointer to the next cell. It is typically defined in C as follows:
    typedef struct LinkedList {
      char value[MAX_VALUE_SIZE];
      struct LinkedList * next;
    } LinkedList;
        
    value = "first cell" value = "second cell
    next = pointer to second cell
    
    next = NULL

  2. Save the ll.c file into your work directory, open it with your favorite text editor. Locate where the open() function is used. Verify that open() is a system call. Find out how many syscalls are used in ll.c.

  3. Study this source code in detail, find out its main purpose. What errors can be raised during execution? Can you explain in which case each of them is raised?

  4. Compile ll.c to a binary file named ll:
    $ gcc -Wall -o ll ll.c

  5. Execute writeToFile. But first, create a file named hello.txt that contains on word per line. For instance, hello\nworld\nhow\nare\nyou\ntoday?.
    $ ./ll hello.txt
    The process should open hello.txt and load it into a linked list. Verify that everything works as expected. Have you understood how the linked list is progressively filled with the file content? Be sure to have understood this before switching to the next questions!

  6. Start the program without any argument:
    $ ./ll
    
    What happens? How could you do to provide a better error message even before open() is called?
    (Help me!) Check that an argument is indeed provided on the command line. You could use argc for instance.

  7. Complete the printListContent function of ll.c. Basically, you should go through the different cells of the list, starting from the first one, and print the value of each cell.

    First, think of how to access each cell. Then, for each cell, you just need to perform a printf on the value of the cell.

    Look at the help that follows only once you have really tried!

    (Help me!) SPOILER!!!

    TRY BEFORE LOOKING AT THIS!



    while(ll != NULL) {
     printf("%s ", ll->value);
     ll = ll->next;
    }
    printf("\n");

  8. Freeing the list. What exactly makes the call to free(ll);? Remember what free makes: it frees the memory allocated at the provide address. What was allocated at this address? Only one cell! So, only one cell is freed with that call.

    Now that you have understood the problem, you are asked to code a function freeLinkedList() that frees the whole linked list given as parameter. Code and test.

    When starting to program with data structures, this is quite frequent to obtain "segmentation fault" errors, which means that you have tried to access to an invalid address. Putting printf in your code to try debugging an allocation error might not be the best solution. A better solution is to use a debugger like gdb. For this, you need to compile your program with debugging information:

    $ gcc -Wall -g -o ll ll.c
    And then you can investigate your error. Execute with gdb (to run type run, to quit type quit, to restart from the beginning type: start):
    $gdb ./ll hello.txt
    ...
    (gdb) run
    ...
    
    
    You should reach your error. gdb is a complex debugger: you will learn more commands of gdb during the next lab. But at least, during this lab, this should give you the line number at which the error occurs in your code.

  9. Implement a function that returns the current size of a linked list:
    int sizeOfList(LinkedList *ll) {
        ...    
    } 
    
    Test with different linked lists.

  10. Implement a function to remove the nth element of a linked list:
    void removeElementAt(LinkedList *ll, int index) {
        ...    
    } 
    
    Test by removing the first element of the list, one in the middle, and the one at the end.

  11. Implement a new C function that stores a new element at the end of the list. Currently, elements in the provided program are stored at the beginning of the list.
    LinkedList* addToTheEndOfTheList(LinkedList *ll, char *content, int startIndex, int lastIndex) {
        ...
    }
    

  12. BONUS: implement a function that saves the linked list to a file.