Project 1: psstat
In this project, you are to develop a Bash shell script (or
others approved by the instructor) to query process information from the
/proc file system. However, all the information about a process must
come from the /proc file system, and using the ps command or similar is
prohibited in this project.
This project is not just about producing a working psstat. It is about
understanding how the kernel exposes process information through /proc,
and how a user-space program turns that into a useful view. You will be
asked to explain your implementation, not just to submit it. Treat the
questions below as part of the deliverable.
GitHub Assignment Submission Setup
-
Provide your GitHub username at:
-
Accept the assignment invitation after you complete the survey above.
-
Submit your work to the assignment Git repository created as a result of accepting the assignment invitation.
Starter Code
The repository upon creation will contain starter code in the src/bash
directory. The starter code is written in bash. If you are programming in
other scripting language that is approved by the instructor, you should create a
directory matching the language in which you are programming in the src
directory.
README File
The top directory of the repository should contain a README file. You shall create the file to provide concise description of your work and the layout of the repository.
.gitignore
Add a .gitignore in the top level directory to prevent accidentally
putting unnecessary files in the repository.
AI Use Disclosure
The use of AI assistants and coding agents (e.g., GitHub Copilot, Claude
Code, ChatGPT, Cursor) is permitted, but must be disclosed. For every
commit that contains AI-generated or AI-assisted content, include a
Co-authored-by trailer in the commit message naming the tool. For example:
Add --list-short implementation
Co-authored-by: GitHub Copilot <copilot@github.com>
Fix comm parsing for names with spaces
Co-authored-by: Claude Code <noreply@anthropic.com>
Commits without such a trailer are taken as the student’s own work. A single “initial commit” containing the entire final script will be treated as incomplete regardless of disclosure. Undisclosed AI use is an academic integrity violation.
Submission
To submit the work, complete the following:
- Your work resides on a GitHub repository. Make sure to push your work to the GitHub repository.
- Do not submit the solution as a single commit. Commit each feature completed as a single commit.
- Make a short presentation and demo in class: 10 minutes, ideally with slides, a demo of the features of the program, and the discussion about the questions in this assignment
The submission deadline and the demo deadline shall be on the class Website.
Requirement
This section describes the requirements for the script you are to develop. The GitHub repository will contain the Bash shell script starter code for the project. You can implement it using a scripting language approved by the instructor; however, to match the learning objectives of the course, Bash shell script is strongly preferred.
-
The name of the shell script shall be
psstat. -
The shell script can obtain process information from only the
/procfile system. -
A user shall use the script in the following scenarios:
-
psstat --helpDisplay a help message and exit. The following is an example run of the command:
~/project1$ ./psstat --help Usage: psstat [OPTION] ... List process information. Options are --list-short list all processes in short format --list-long list all processes in long format --list-name-has <name_part> list all processes whose name has name_part in long format --list-pid-is <pid> list status of the process whose pid is <pid> --list-sched-policy-is <policy_number> list all processes whose CPU scheduling policy number is <policy_number> in long format ~/project1$You may consider the following suggestions:
-
To output messages on the Standard Output or the Standard Error device, you generally use
bash’sechocommand. To view the online help message of the command, issue commandhelp echoinbash. -
If you wish to control the format of the output, you may also use the Linux system’s
printfcommand. To view the online manual of the command, issue commandman printf.
-
-
psstat --list-shortList process id of all processes in the system. The following is an example run of the command:
~/project1$ psstat --list-short PID 1 10 101 103 105 106 10852 ~/project1$You may consider the following suggestions:
- Examine the “Files and directories” section in
/proc’s manual page. For each process, there is a sub-directory named after the process’s PID in the/procdirectory. - Examine
bash’sfororwhileloop in the “Compound Commands” section, and the “Parameter Expansion” section inbash’s manual page. Alternatively, you can view their brief help messages using commandshelp forandhelp whileinbash.
- Examine the “Files and directories” section in
-
psstat --list-longList process id, process state, image name, and command line arguments of all processes in the system. The following is an example run of the command:
$ ./psstat --list-long PID CMD ST CMD_ARGS 1 "systemd" S "'/lib/systemd/systemd' '--system' '--deserialize' '33'" 10 "rcu_sched" I 20774 "kworker/0:0-ata_sff" I 9255 "sshd" S "'sshd: cisc7310@pts/0'" 9256 "bash" S "'-bash'" 9367 "test 123" S "'./test 123' '1' '2' '3' 'abc' 'a' 'b' 'c' 'cde fgh'" 9427 "kworker/u2:0-events_unbound" I 97 "ata_sff" I 99 "scsi_eh_0" S ~/project1$You may consider the following suggestions:
-
Examine the manual page of
/procfor/proc/${pid}/command/proc/${pid}/stat. You can retrieve the filename of the executable (or theCMD) from either/proc/${pid}/commor/proc/${pid}/stat. If you retrieve it from/proc/${pid}/stat, note that the filename there is in parentheses, and you ought to remove the parentheses. -
Examine the manual page of UNIX command
cutthat can divide a line of text to fields and retrieve desired fields. -
To remove prefix, suffix, or else from a string, you can take advantage of
bash’s parameter expansion functionality. You should examine the manual page carefully for this. -
UNIX has a few commands that support pattern matching and extraction using regular expressions. In the following example, we use the
sedcommand to remove pattern like(CISC dddd)wheredis a digit from a string:~/project1$ echo "The (CISC 7310) and (CISC 3115) courses are exciting classes." | \ sed -E -e 's/\(CISC [[:digit:]]+\)//g' The and courses are exciting classes. ~/project1$In the example below, we use the
grepcommand to extract substrings that match pattern likeCISC ddddwheredis a digit from a string:~/project1$ echo "The (CISC 7310) and (CISC 3115) courses are exciting classes." | \ grep -E -o "CISC [[:digit:]]+" CISC 7310 CISC 3115 ~/project1$To learn more about regular expressions in UNIX systems, view its manual page by command
man 7 regex. A few UNIX commands supporting pattern matching and extraction using regular expressions and often used in shell scripts includesed,grep, andawk.
-
-
psstat --list-name-has <name_part>List process id, process state, image name, and command line arguments of all processes whose image name contains
<name_part>in the system. The following is an example run of the command:~/project1$ ./psstat --list-name-has "est 1" PID CMD ST CMD_ARGS 29320 "test 123" S "'./test 123' '1' '2' '3' 'abc' 'a' 'b' 'c' 'cde fgh'" ~/project1$Another example is as follows:
~/project1$ ./psstat --list-name-has bash PID CMD ST CMD_ARGS 29209 "bash" S "'-bash'" 29313 "bash" S "'-bash'" 6451 "bash" S "'-bash'" ~/project1$You may consider the following suggestions:
-
To determine whether a string contains a substring, you may use wild card character
*or regular expression. For example, the following command determines whether theThe CISC 7310 classstring contains the substringCISC 7310using the*wild card character:~/project1$ if [[ "The CISC 7310 class" == *"CISC 7310"* ]]; then > echo "Found CISC 7310" > else > echo "Didn't find CISC 7310" > fi Found CISC 7310 ~/project1$while the following uses a regular expression:
~/project1$ if [[ "The CISC 7310 class" =~ .*"CISC 7310".* ]]; then > echo "Found CISC 7310" > else > echo "Didn't find CISC 7310" > fi Found CISC 7310 ~/project1$Resting on your understanding on parameter expansion in
bash, you can also achieve the same using pattern substitution for parameter expansion inbash:~/project1$ msg="The CISC 7310 class" ~/project1$ msgnew=${msg/CISC 7310/} ~/project1$ if [[ ${#msg} -ne ${#msgnew} ]]; then > echo "Found CISC 7310" > else > echo "Didn't find CISC 7310" > fi Found CISC 7310 ~/project1$
-
-
psstat --list-pid-is <pid>List selected process status information for the process whose pid is
<pid>. The following is an example run of the command:~/project1$ ./psstat --list-pid-is 29320 pid: 29320 comm: (test 123) state: S minflt: 76 majflt: 0 utime: 0 clock ticks stime: 0 clock ticks num_threads: 1 vsize: 2449408 bytes rss: 125 pages ~/project1$ -
psstat --list-sched-policy-is <policy_number>List selected process status information for the process whose CPU scheduling policy is
<policy_number>. The following is an example run of the command:~/project1$ ./psstat --list-sched-policy-is 1 PID CMD ST SCHED_POLICY CMD_ARGS 12 "migration/0" S SCHED_FIFO(1) 29 "watchdogd" S SCHED_FIFO(1) 322 "irq/10-vmwgfx" S SCHED_FIFO(1) ~/project1$The following is another example:
~/project1$ ./psstat --list-sched-policy-is 0 PID CMD ST SCHED_POLICY CMD_ARGS 1 "systemd" S SCHED_NORMAL(0) "'/lib/systemd/systemd' '--system' '--deserialize' '33'" 10 "rcu_sched" I SCHED_NORMAL(0) 29320 "test 123" S SCHED_NORMAL(0) "'./test 123' '1' '2' '3' 'abc' 'a' 'b' 'c' 'cde fgh'" 7056 "psstat" S SCHED_NORMAL(0) "'/bin/bash' './psstat' '--list-sched-policy-is' '0'" ~/project1$You may consider the following suggestions:
- The CPU scheduling policy is a field in the
/proc/${pid}/statfile. - As the manual page of
procsuggests, you can retrieve the textual information of the scheduling policy, e.g.,SCHED_NORMALfrom the/usr/include/linux/sched.hfile.
- The CPU scheduling policy is a field in the
-
Questions
Answer the following questions in a file named ANSWERS.md in the top
directory of your repository. Each answer should be short (a few sentences
or a small code/transcript excerpt). Where a question asks you to run
something, include the command and its output.
-
Annotated execution trace. Pick one of the six modes (e.g.,
--list-sched-policy-is 0). Run it understraceand submit the trace. For each/procfile your script reads, state concisely (a) which file it is, (b) which field in that file you are extracting, and (c) how you parse it. -
The
readsyscall count. How many times does your script callread(2)on files under/procwhen running--list-short? Justify your answer by examining the trace, not by guessing. Providing the trace. -
Break it on purpose. Modify your script to read
/proc/1/statfrom a non-root user. What happens? Which syscall returns the error? What is theerrno? Why does the kernel allow this even though/proc/1/is “owned” by root? -
Field-counting in
/proc/${pid}/stat. Thestatfile’scommfield is in parentheses and may contain spaces and parentheses. Explain why a naivecut -d' ' -f2fails on a process namedtest (123). What is the correct way to extractcomm, and why does the kernel wrap it in parentheses in the first place? -
PIDs are not contiguous. In the
--list-shortexample, the PIDs are something like1, 10, 101, 103, 105, 106, 10852. Why are there gaps? Does your script assume PIDs are contiguous, and if so, what breaks? -
/procis not a real filesystem./proc/${pid}/statreportsutimeandstime. Where do these numbers actually come from? Are they stored on disk? If not, how does reading the file work, i.e., what does the kernel do when youread(2)it? -
Compare with
ps. Runps -eo pid,stat,comm,argsand compare its output with./psstat --list-long. Identify at least three differences. For each, explain which/procfilepsis likely reading and which field it is deriving that your script does not. -
The scheduling policy mapping. The spec says the textual policy name (e.g.,
SCHED_NORMAL) comes from/usr/include/linux/sched.h. Read that header and list everySCHED_*constant and its numeric value. Is the mapping from number to name one-to-one? Are there numbers that appear in/proc/${pid}/statbut have no constant in that header? -
Reproduce a failure. Under what conditions would
./psstat --list-pid-is <pid>fail with a “No such file or directory” error even though the process exists? Give a concrete scenario. -
Design note. In 0.5 - 1 pages, explain how your script discovers processes, how it parses
/proc/${pid}/stat, and what happens if a process exits while you are reading it. Include at least one thing you tried that did not work and how you resolved it.