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

  1. Provide your GitHub username at:

    CISC 7310XBrightspace Survey

  2. Accept the assignment invitation after you complete the survey above.

  3. 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:

  1. Your work resides on a GitHub repository. Make sure to push your work to the GitHub repository.
  2. Do not submit the solution as a single commit. Commit each feature completed as a single commit.
  3. 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.

  1. The name of the shell script shall be psstat.

  2. The shell script can obtain process information from only the /proc file system.

  3. A user shall use the script in the following scenarios:

    1. psstat --help

      Display 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:

      1. To output messages on the Standard Output or the Standard Error device, you generally use bash’s echo command. To view the online help message of the command, issue command help echo in bash.

      2. If you wish to control the format of the output, you may also use the Linux system’s printf command. To view the online manual of the command, issue command man printf.

    2. psstat --list-short

      List 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:

      1. 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 /proc directory.
      2. Examine bash’s for or while loop in the “Compound Commands” section, and the “Parameter Expansion” section in bash’s manual page. Alternatively, you can view their brief help messages using commands help for and help while in bash.
    3. psstat --list-long

      List 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:

      1. Examine the manual page of /proc for /proc/${pid}/comm and /proc/${pid}/stat. You can retrieve the filename of the executable (or the CMD) from either /proc/${pid}/comm or /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.

      2. Examine the manual page of UNIX command cut that can divide a line of text to fields and retrieve desired fields.

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

      4. UNIX has a few commands that support pattern matching and extraction using regular expressions. In the following example, we use the sed command to remove pattern like (CISC dddd) where d is 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 grep command to extract substrings that match pattern like CISC dddd where d is 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 include sed, grep, and awk.

    4. 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:

      1. To determine whether a string contains a substring, you may use wild card character * or regular expression. For example, the following command determines whether the The CISC 7310 class string contains the substring CISC 7310 using 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 in bash:

        ~/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$
        
    5. 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$
      
    6. 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:

      1. The CPU scheduling policy is a field in the /proc/${pid}/stat file.
      2. As the manual page of proc suggests, you can retrieve the textual information of the scheduling policy, e.g., SCHED_NORMAL from the /usr/include/linux/sched.h file.

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.

  1. Annotated execution trace. Pick one of the six modes (e.g., --list-sched-policy-is 0). Run it under strace and submit the trace. For each /proc file 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.

  2. The read syscall count. How many times does your script call read(2) on files under /proc when running --list-short? Justify your answer by examining the trace, not by guessing. Providing the trace.

  3. Break it on purpose. Modify your script to read /proc/1/stat from a non-root user. What happens? Which syscall returns the error? What is the errno? Why does the kernel allow this even though /proc/1/ is “owned” by root?

  4. Field-counting in /proc/${pid}/stat. The stat file’s comm field is in parentheses and may contain spaces and parentheses. Explain why a naive cut -d' ' -f2 fails on a process named test (123). What is the correct way to extract comm, and why does the kernel wrap it in parentheses in the first place?

  5. PIDs are not contiguous. In the --list-short example, the PIDs are something like 1, 10, 101, 103, 105, 106, 10852. Why are there gaps? Does your script assume PIDs are contiguous, and if so, what breaks?

  6. /proc is not a real filesystem. /proc/${pid}/stat reports utime and stime. 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 you read(2) it?

  7. Compare with ps. Run ps -eo pid,stat,comm,args and compare its output with ./psstat --list-long. Identify at least three differences. For each, explain which /proc file ps is likely reading and which field it is deriving that your script does not.

  8. 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 every SCHED_* constant and its numeric value. Is the mapping from number to name one-to-one? Are there numbers that appear in /proc/${pid}/stat but have no constant in that header?

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

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