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.).

Trick. In Linux, do you know that you can do a copy/paste very easily with your mouse only? Simply select some text with your mouse, then move your mouse pointer to the place where you want to copy this text, and then click on the middle mouse button ... the text is copied!

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?
  2. $ man write
    
  3. Similarly, try to figure out if the following command are bash commands, syscalls, or C library functions: "read", "print", "printf", "malloc", "exit", "getpid", "ps"

  4. (Help me!) Use "man -s2 f" to know if a function "f" is a syscall or not

III. Using system calls



During this exercise, you will learn how to compile a C program, how to correct errors&warnings, and how to use Linux system calls. You will also discover how to manipulate files from a C program.
  1. Save the writeToFile.c file into your work directory, open it with your favourite text editor. You should be able to locate the use of the open() function. Verify that open() is a system call. Then, find how many syscalls are used in writeToFile.c.


  2. Now, read the code of this program in detail, i.e., find out its main purpose. What errors could occur? Could you explain why?

  3. Compile writeToFile.c to a binary file called writeToFile:
  4. $ gcc -Wall -o writeToFile writeToFile.c
    

  5. Execute writeToFile as follows:
  6. $ ./writeToFile /tmp/test hello
    
    The process should fill the file /tmp/test with "hello". Test and verify the content of the file.

  7. Now, use the program in such a way that it fails to fill the file. Test.
  8. (Help me!) What happens if the program tries to write in a file to which you don't have the right to write?


  9. Currently, when there is an error, the program exits and returns value "1" to the bash. We would like to give more information to the user of this program when an error occurs. For this, first use the manual page of the open syscall. At the end of the manual page, there should be a list of possible errors provided. Pick up one of them you are able to reproduce. When open is called and returns a negative value, it means that there was an error. To get the value of this error, add this line to the top of your program:
    #include <errno.h>
    
    Now, each time you call a syscall, you can read the content of the variable "errno" (without having to declare it: it is already declared in errno.h), and you can compare this value to values provided in the manual page of e.g. open:
    if (errno == EINTR) {
       ...
    } else if (errno == EINVAL) {
      ....
    }
    
    Now, add the management of at least one error you know how to reproduce: check that you obtain the expected error number, and give more information to the user when this error occurs.

  10. You may have noticed that the program asks the write syscall to write all the characters at once, i.e. it gives as parameter to write: "strlen(toBeWritten)". We now assume that write() can write only one character at a time, so you are now allowed to use write() only in the following way:
    write(int fd, const void *buf, 1);
    
    Program a new version with this restriction on write, and make sure that it really works as expected (use a new name for your file: writeOnetoFile.c).


    What the provided code doesWhat your code should do
    write(all characters at a time)
    
    
    while(not over) {
        write(one character at a time)
    }
    


  11. Now, instead of using an input text, the new program (called readThenWrite) should first read all data from an input file and then write back these data to a destination file.

    1. You first need to change how arguments are handled: the first argument should be the input file, the second one the output file

    2. Then, read data from the input file. To store input data in a buffer, you may need to first evaluate the size of the input file. To do this, you can use lseek(). By the way, is lseek() a syscall? Also, do not forget to handle possible errors.

    3. After the read command is over, write the data to the output file. Compile and test. Again, try to trigger errors to figure out if your error management works as expected. Also, what happens if you provide too few or too many arguments?

  12. Bonus work: Reading all the input file at once, and then outputing all data at once to the destination file is not very efficient if the file is big: it consumes a lot of memory to be allocated first. You can try for instance with a 1GB file and measure the time it takes to read and write it back:
  13. time ./ReadThenWrite /tmp/mybigfile /tmp/output
    
    To reduce the time it takes for the copy, we could use an intermediate buffer:

    What the initial code doesWhat your code should now do
    read(all characters at a time)
    write(all characters at a time)
    
    
    while(not over) {
        read(a few kilobytes)
        write(this few kilobytes)
    }
    

    Program, test, and prove that it saves time (and memory). For timing aspects, you can use the time command of the shell. Do understand the different values that time outputs to conclude.

    Now, let's say you want to write the same input content to two output files. Would it be more efficient to write the entire content to the first file and then to the second, or to write to both files incrementally?