Our journey through the operating system starts in 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, 15 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
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
In the default mode (no extra arguments), simply print out the information and then terminate the program. You should also support a live mode where the terminal display updates every second, as shown below:
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 :
Simply cd /proc in your shell and then run ls to view the files. You’ll see process IDs and several other virtual files that are updated dynamically with system information.
Each line shown above in the process listing corresponds to a numbered directory in /proc .
Check out the man page: man proc . The manual has a complete description of every file and directory stored under /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:
The open() , read() , and close() system calls for reading file data Tokenizing text files
opendir and readdir functions for listing directory contents
stat for getting file information getpwuid() to map user IDs to user names Argument parsing with getopt
Load averages, calculating CPU usage, and Linux tasks
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):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:
You can use the chdir system call to make supporting the -p option easier. Just chdir to the specified directory and open files as relative paths.
Remember to close the files/directories you open! If too many file descriptors are left open, subsequent open calls will fail.
Truncate strings that are too long to display (applicable to the process and user names). Otherwise, your formatting won’t be correct. See the example printf format string below for the column lengths.
Use the amount of active memory when reporting memory usage.
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:
Years Days Hours Minutes Seconds
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%.
Live View
Usually printing text to the terminal will scroll its output (newest text on the bottom with older text scrolling up). In live mode, you will need to update the display in place without letting the terminal
scroll. To do this, print ANSI Escape Codes to manipulate the terminal’s cursor position and then print updated text over the top of the old text.
Escape codes are outputted the same as any other text, with printf , puts , etc. — you probably already use n often. These codes are treated as a special case by the terminal and allow it to do things like display colors or basic interfaces.
These escape codes will be helpful:
r – go to the start of the current line
33[A – go up one line
33[?25l – hide the terminal cursor (only needs to be done once)
You might notice that after killing your inspector process with ^C the cursor is still hidden. To get it back, run a terminal UI program such as top or vim . If you want to get fancy, you are welcome to detect the program’s termination and restore the cursor yourself, but this is not required.
Formatting
You should format your output as shown in the example above. For the process list, the printf format string used is:
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 , scanf , 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 reentrant or 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.
DescriptionIn this final assignment, the students will demonstrate their ability to apply two ma
Path finding involves finding a path from A to B. Typically we want the path to have certain properties,such as being the shortest or to avoid going t
Develop a program to emulate a purchase transaction at a retail store. Thisprogram will have two classes, a LineItem class and a Transaction class. Th
1 Project 1 Introduction - the SeaPort Project series For this set of projects for the course, we wish to simulate some of the aspects of a number of
1 Project 2 Introduction - the SeaPort Project series For this set of projects for the course, we wish to simulate some of the aspects of a number of