Operating Systems 2018F: Assignment 2

From Soma-notes

Please submit the answers to the following questions via CULearn by 2:30 PM on Wednesday, October 10, 2018. There are 20 points in 10 questions.

Submit your answers as a single text file named "<username>-comp3000-assign2.txt" (where username is your MyCarletonOne username). The first four lines of this file should be "COMP 3000 Assignment 2", your name, student number, and the date of submission. You may wish to format your answers in Markdown to improve their appearance.

No other formats will be accepted. Submitting in another format will likely result in your assignment not being graded and you receiving no marks for this assignment. In particular do not submit an MS Word or OpenOffice file as your answers document!

Don't forget to include what outside resources you used to complete each of your answers, including other students, man pages, and web resources. You do not need to list help from the instructor, TA, or information found in the textbook.

Questions

  1. [2] Assume you have a file A. You type ln A B in order to create file B. What is the relationship between the return of lstat() on A versus B? Explain briefly.
  2. [2] Assume you have a file A. You type ln -s A B in order to create file B. What is the relationship between the return of lstat() on A versus B? Explain briefly.
  3. [2] How could you modify 3000test.c so it can report on what a file's user ID and group ID are and the corresponding username and group name? Specify the changes you make rather than writing all the code out. (In other words, code a solution and explain the changes you made here.)
  4. [2] If you change line 68 of 3000test.c to be data[i] = 'A'; (from count++;), what will the program do? Explain briefly.
  5. [2] What does setup_comm_fn() do in 3000shell?
  6. [2] How can you modify 3000pc so the consumer permanently stops consuming once it finds an empty queue?
  7. [2] What would happen to 3000pc if we replaced lines 341-347 with s = (shared *) malloc(sizeof(shared));? Why?
  8. [2] In 3000pc, what happens if you remove the calls to kill()? What does this tell you about the roles of signals in this program?
  9. [2] Is it possible to predict the output of /dev/random? Explain briefly.
  10. [2] Do sem_wait() and sem_post() generate system calls? (Be sure to check!) Why?

Solutions

  1. lstat(A) and lstat(B) return exactly the same thing because they are both geting information on the same inode (B is hard linked to A, so both A and B refer to the same inode).
  2. lstat(A) and lstat(B) return different results because B is a symbolic link to A. So, lstat(B) gives information on the inode of the symbolic link referred to by B, while lstat(A) gives information on the file inode referred to by A.
  3. User ID: statbuf.st_uid, username: getpwuid(User ID).pw_name, Group ID: statbuf.st_gid, group name: getgrgid(Group ID).gr_name. Add these to the printf's around line 53. Note these functions have their own static buffer potentially so you should copy the resultant strings to a local buffer.
  4. The program will terminate with a segfault or similar signal because the data array is read only. It is read only because the file was mmap'd into memory with only the PROT_READ protection. (If you add PROT_WRITE and open the file for writing you'd be able to modify the array and the mapped file on disk.)
  5. setup_comm_fn() creates the string "/proc/<pid>/comm" in the character array pointed to by comm_fn where <pid> is the pidstr (character arrary) given as input.
  6. To get the consumer to stop consuming when the queue is empty (and exit), replace lines 217-219 (which run when the current word is a null pointer) with a call to exit().
  7. If the call to mmap is replaced with a call to malloc, the queue is no longer shared between the producer and consumer, because fork logically duplicates all memory (including that allocated by normal calls to malloc). There is thus no shared data structure between the producer and consumer, and so they have no way of communicating. As a result the producer will fill its buffer and wait forever while the consumer waits forever with an empty buffer.
  8. When you remove calls to kill, the program functions correctly except the producer and consumer wait for 100 seconds when the queue is full and empty, respectively. This indicates that the signals are only used to interrupt sleep in the waiting process.
  9. Normally it should not be possible to predict the output of /dev/random, as its entire purpose is to produce output that is unpredictable, even against a malicious adversary. But any random number generator is only as good as its inputs, and the driver for /dev/random draws upon sources that could in principle be compromised (i.e., turned into sources of predictable bits rather than unpredictable bits). Network packets can be controlled, hard drive behavior can be modified or virtualized, and CPUs can be compromised. If you can predict the behavior of the inputs to /dev/random, you can predict its output as well.
  10. sem_wait() and sem_post() do not generate system calls; instead, they make use of special CPU instructions that allow memory to be both tested and modified in one atomic step. Such an implementation is much faster than one based on system calls, and fast synchronization & locking is a key feature of semaphores. (Actually they can produce system calls, but only when it has to wait on a lock; the waiting (blocking) is implemented using system calls such as futex. See the futex man page.)