CS 326 Operating Systems

Project 1: System Inspector (v 1.0)

Starter repository on GitHub: https://classroom.github.com/a/NL5zCUW1

Our journey through the operating system starts in userland (user space), outside the kernel. In this project, we’ll implement a Unix utility that inspects the system it runs on and creates a summarized report for the user. If you’ve ever used the top command from a shell, our program will be somewhat similar. To give you an idea of how your program will work, here’s a quick example:

[magical-unicorn:~/P1-malensek]$ ./inspector
System Information
------------------
Hostname: magical-unicorn
Kernel Version: 4.20.3-arch1-1-ARCH
Uptime: 32 minutes, 35 seconds

Hardware Information
--------------------
CPU Model: AMD EPYC Processor (with IBPB)
Processing Units: 2
Load Average (1/5/15 min): 0.15 0.06 0.01
CPU Usage:    [##########----------] 50.3%
Memory Usage: [--------------------] 4.6% (0.0 GB / 1.0 GB)

Task Information
----------------
Tasks running: 88
Since boot:
    Interrupts: 44349
    Context Switches: 88340
    Forks: 421

  PID |        State |                 Task Name |            User | Tasks
------+--------------+---------------------------+-----------------+-------
    1 |     sleeping |                   systemd |            root |     1
    2 |     sleeping |                  kthreadd |            root |     1
    3 |         idle |                    rcu_gp |            root |     1
    4 |         idle |                rcu_par_gp |            root |     1

(the entire list of processes is printed -- truncated for brevity)

To get this information, you will use the proc, the process information pseudo-filesystem. While there are other ways to get the information displayed above, you are restricted to using proc in this assignment. There are two great resources for finding out what information is available in proc:

For a quick example, try running cat /proc/uptime. You’ll see the number of seconds the system has been running printed to the terminal.

In this assignment, you will get experience working with:

Each portion of the display can be toggled with command line options. We’ll let the program do the talking by printing usage information (-h option):

[magical-unicorn:~/P1-malensek]$ ./inspector -h
Usage: ./inspector [-ahlrst] [-p procfs_dir]

Options:
    * -a              Display all (equivalent to -lrst, default)
    * -h              Help/usage information
    * -l              Task List
    * -p procfs_dir   Change the expected procfs mount point (default: /proc)
    * -r              Hardware Information
    * -s              System Information
    * -t              Task Information

So the task list, hardware information, system information, and task information can all be turned on/off with the command line options. By default, all of them are displayed.

Pay particular attention to the -p flag. This allows us to change the directory where proc is mounted (/proc by default). We will use this option to test your code with our own pre-populated copy of proc.

Populating the Output

Here’s some tips to guide your implementation:

Uptime

When calculating uptime, don’t report years, days, or hours if their respective values are 0. If a machine has just booted up, you’ll display Uptime: 0 minutes, 42 seconds, for example. The fields you need to support are:

CPU Usage

CPU usage is calculated by sampling over a period of time, i.e., the CPU was active for 70% of one second. You should record the CPU usage, sleep for one second, and then get a second reading to determine the usage percentage. The CPU metrics in /proc/stat will add up to 100% because idle time is included. You’ll need to track idle time separately, so the calculation will look something like:

1 - ( (idle2 - idle1) / (total2 - total1) )

If the CPU usage percentage is NaN (not a number), report 0%.

Formatting

You should format your output as shown in the example above. For the process list, the printf format string used is:

printf("%5s | %12s | %25s | %15s | %s \n",
	"PID", "State", "Task Name", "User", "Tasks");

Implementation Restrictions

Restrictions: you may use any standard C library functionality. External libraries are not allowed unless permission is granted in advance. Your code must compile and run on your VM set up with Arch Linux as described in class – failure to do so will receive a grade of 0.

While there are several ways to retrieve the system information displayed by your project, you must retrieve the data from /proc only.

One of the major components of this assignment is reading and parsing text files. To read the files, you are required to use the read system call instead of the fancier C library functions like fgets, getline, etc. You are also required to write your own string tokenization functionality with strspn and strcspn – don’t use strtok!

Rationale: we’re using read here to get familiar with how I/O works at a lower level. You will need to be able to understand read for subsequent assignments. As for strtok, it has several pitfalls (including not being thread safe) that make it a bad choice. We are writing our own version of strsep with strspn and strcspn so that when we need to parse more complicated inputs in later projects we’ll be able to do so.

Failure to follow these guidelines will result in severe deductions or a 0.

Testing Your Code

Check your code against the provided test cases. You should make sure your code runs on your Arch Linux VM. We’ll have interactive grading for projects, where you will demonstrate program functionality and walk through your logic.

Submission: submit via GitHub by checking in your code before the project deadline. You must include a makefile with your project. As part of the testing process, we will check out your code and run make to build it.

Grading

Extra Credit

Changelog