CMSC216 Lab09: Fork/Wait and Stat
- Due: 11:59pm Sun 16-Nov-2025 on Gradescope
- Approximately 1.00% of total grade
CODE DISTRIBUTION: lab09-code.zip
CHANGELOG: Empty
Table of Contents
1 Rationale
The fork() and wait() system calls are among the most basic
facilities to create and coordinate processes in Unix systems. While
their semantics can seem simple at first, use of fork() in
particular can be a bit deceptive. This exercise illustrates as much with
a simple looking program with somewhat unexpected behavior. It also
gives practice on how a parent process can coordinate its execution in
a limited fashion with child processes and receive a small amount of
information about the child process via collecting their exit codes.
Frequently systems programs must check for the existence of file and
interrogate their properties. The first exercise studies two common
system calls for this task, access() and stat(). It employs them
in a few simple tasks to acquaint students with their use.
Associated Reading
- Bryant and O'Hallaron CSAPP Ch 8.4 discusses
fork() / wait(), their uses in creating and coordinating processes, and gives enough basic coverage to inform on Problem 1. - Bryant and O'Hallaron CSAPP Ch 10.6 discusses file metadata and how
it is accessed via
stat()and related functions. The manual page entry foraccess()is a good source of information on its use.
Grading Policy
Credit for this exercise is earned by completing the code/asnwers here
and submitting a Zip of the work to Gradescope. Students are
responsible to check that the results produced locally via make test
are reflected on Gradescope after submitting their completed
Zip. Successful completion earns 1 Engagement Point.
Lab Exercises are open resource/open collaboration and students are encouraged to cooperate on labs. Students may submit work as groups of up to 5 to Gradescope: one person submits then adds the names of their group members to the submission.
See the full policies in the course syllabus.
2 Codepack
The codepack is linked at the top of this document. Always download it and unzip/unpack it. It should contain the following files which are briefly described.
| File | Use | Description |
|---|---|---|
QUESTIONS.txt |
EDIT | Questions to answer: fill in the multiple choice selections in this file. |
fork_me_main.c |
EDIT | PROBLEM 1 C file to edit |
stat_demo.c |
Study | PROBLEM 2 demo showing access() / stat() system calls |
newer_file.c |
EDIT | PROBLEM 2 code outline to complete |
QUESTIONS.txt.bk |
Backup | Backup copy of the original file to help revert if needed |
Makefile |
Build | Enables make test and make zip |
testy |
Testing | Test running scripts |
test_lab09.org |
Testing | Tests for this lab |
test_code.org |
Testing | Tests for code problems allowing individual testing |
test_order_pids |
Testing | Filter to normalize the PIDs in fork_me |
gradescope-submit |
Misc | Allows submission to Gradescope from the command line |
3 QUESTIONS.txt File Contents
Below are the contents of the QUESTIONS.txt file for the exercise.
Follow the instructions in it to complete the QUIZ and CODE questions
for the exercise.
_________________
LAB09 QUESTIONS
_________________
Exercise Instructions
=====================
Follow the instructions below to experiment with topics related to
this exercise.
- For sections marked QUIZ, fill in an (X) for the appropriate
response in this file. Use the command `make test-quiz' to see if
all of your answers are correct.
- For sections marked CODE, complete the code indicated. Use the
command `make test-code' to check if your code is complete.
- DO NOT CHANGE any parts of this file except the QUIZ sections as it
may interfere with the tests otherwise.
- If your `QUESTIONS.txt' file seems corrupted, restore it by copying
over the `QUESTIONS.txt.bk' backup file.
- When you complete the exercises, check your answers with `make test'
and if all is well, create a zip file with `make zip' and upload it
to Gradescope. Ensure that the Autograder there reflects your local
results.
- IF YOU WORK IN A GROUP only one member needs to submit and then add
the names of their group.
PROBLEM 1 QUIZ: Questions on fork_me.c
======================================
Analyze the `fork_me.c' application then compile and run it. Compiling
can be done via a `make'. Answer the questions below about its
behavior.
How many total processes are created by running this program including
the initial process?
- ( ) 3
- ( ) 4
- ( ) 5
- ( ) 16
Which of the following best describes the relationship between the
processes created by running this program?
- ( ) There is a "chain" of processes with single parent, single
child, single grand child, etc.
- ( ) There is a "fan" of processes with a single parent and multiple
children
- ( ) There is a lobsided "tree" of processes with a single parent,
several children, some of which have grand children, some of which
have great grand children, etc.
- ( ) There are several individual parents each of which has a single
child.
Concerning when the processes complete and produce their FINISH
output...
- ( ) The order that the processes complete is always the same.
- ( ) The entire output order varies and cannot be predicted
- ( ) Portions of the output appear predictably but other portions
vary
- ( ) Only the process IDs vary but the printing order does not change
Check ALL that are true about the initial version of he `fork_me.c'
program
- ( ) Sometimes when running the program, a process will report its
Parent PID as 1
- ( ) All processes report a global_total of 4
- ( ) Sometimes the START message will appear after some FINISH
messages
- ( ) The intended output of child and grandchild processes print more
"--" symbols does not work and all processes appear at the same
level
PROBLEM 1 CODE: Create order for fork_me.c
==========================================
Modify the `fork_me.c' program to fulfill the following requirements
1. Every run of the program leads to the same ordering of output
between parent, child, grandchild, etc. processes
2. Parent processes pause each time a child is created and do not
proceed until a child process finishes.
3. The parent process examines the status of the child process and
extracts its exit code / return value and adds it to the
`global_total' variable.
The code modifications required include the use of some of the
following system calls and associated macros.
-----------------------------------------------------------------------------------------------------------------------------
Call/Macro Effect
-----------------------------------------------------------------------------------------------------------------------------
wait(NULL); Wait for any immediate child process to finish
wait(&status); Wait for any immediate child process to finish AND store info about its completion
waitpid(cpid,NULL,0); Wait specifically for child cpid to finish
waitpid(cpid,&status,0); Wait specifically for child cpid to finish AND store info about its completion
WIFEXITED(status) Evaluates to "truthy" if status contains info on a process that exited normally
WEXITSTATUS(status) For processes that exited normally, extracts the exit code / return value for the program
WIFSIGNALLED(status) Evaluates to "truthy" if status contains info on a process that were terminated due to errors
WTERMSIG(status) For processes that were terminated, returns the Signal number related to the cause of termination
-----------------------------------------------------------------------------------------------------------------------------
Not all of these need be used in `fork_me.c' but they may all be
useful in an upcoming project.
You can test your code `make test-code testnum=1'.
NOTE that since the PIDs from run to run are unpredictable, the `make
test-code' command uses the `test_order_pids' to create consistent
PIDs for testing purposes.
EXAMPLE:
,----
| >> ./fork_me
| START| parent_pid: 1010387 pid: 568951
| FINISH| pid: 568951 parent_pid: 1010387 global_total: 4
| --FINISH| pid: 568953 parent_pid: 568951 global_total: 4
| ----FINISH| pid: 568954 parent_pid: 568952 global_total: 4
| ----FINISH| pid: 568957 parent_pid: 568953 global_total: 4
| ----FINISH| pid: 568956 parent_pid: 568952 global_total: 4
| ----FINISH| pid: 568960 parent_pid: 568955 global_total: 4
| ----FINISH| pid: 568961 parent_pid: 568952 global_total: 4
| --FINISH| pid: 568955 parent_pid: 568951 global_total: 4
| --FINISH| pid: 568952 parent_pid: 568951 global_total: 4
| ------FINISH| pid: 568964 parent_pid: 1 global_total: 4
| ------FINISH| pid: 568965 parent_pid: 1 global_total: 4
| ----FINISH| pid: 568962 parent_pid: 1 global_total: 4
| ------FINISH| pid: 568959 parent_pid: 1 global_total: 4
| --FINISH| pid: 568958 parent_pid: 568951 global_total: 4
| ------FINISH| pid: 568963 parent_pid: 1 global_total: 4
| --------FINISH| pid: 568966 parent_pid: 1 global_total: 4
|
| >> ./fork_me | ./test_order_pids
| START| parent_pid: 101 pid: 100
| FINISH| pid: 100 parent_pid: 101 global_total: 4
| --FINISH| pid: 102 parent_pid: 100 global_total: 4
| --FINISH| pid: 103 parent_pid: 100 global_total: 4
| ----FINISH| pid: 104 parent_pid: 102 global_total: 4
| --FINISH| pid: 105 parent_pid: 100 global_total: 4
| ----FINISH| pid: 106 parent_pid: 105 global_total: 4
| ------FINISH| pid: 107 parent_pid: 106 global_total: 4
| ----FINISH| pid: 108 parent_pid: INIT global_total: 4
| ----FINISH| pid: 109 parent_pid: INIT global_total: 4
| ------FINISH| pid: 110 parent_pid: INIT global_total: 4
| ------FINISH| pid: 111 parent_pid: INIT global_total: 4
| ----FINISH| pid: 112 parent_pid: INIT global_total: 4
| --------FINISH| pid: 113 parent_pid: 111 global_total: 4
| ----FINISH| pid: 114 parent_pid: INIT global_total: 4
| --FINISH| pid: 115 parent_pid: INIT global_total: 4
| ------FINISH| pid: 116 parent_pid: INIT global_total: 4
`----
PROBLEM 2 QUIZ: Questions on stat_demo.c
========================================
Analyze the `stat_demo.c' program. Compile and run it via
,----
| >> make stat_demo
| ...
| >> ./stat_demo somefile.txt
| ...
| >> ./stat_demo a_dirname/
`----
Finally, you can contrast the behavior of `filestats.c' to the shell
command `stat' which provides similar functionality.
Answer the following questions about how the system call works.
File Access
~~~~~~~~~~~
Which of the filling best describes how the `access()' system call is
used?
- ( ) It alters read/write access to a file by adjusting its mode bits
- ( ) It is called to determine if a file exists using the `F_OK' flag
- ( ) It ensures a file exists and can be accessed by creating if
necessary
- ( ) It must be called before `stat()' in order to initialize a
`struct stat' data structure
File Size
~~~~~~~~~
How does `stat()' report the Size of a file?
- ( ) An integer is passed to the calls to be set to the size
- ( ) The return value is the number of bytes in the file
- ( ) The size is printed to standard output during the function call
- ( ) The field `sb.st_size' contains the number of bytes in file
File Kind
~~~~~~~~~
`stat()' reports the "kind" of file being queried. How is this
information used in `stat_demo.c'?
- ( ) The field `sb.st_filetype' is set to a string like "file" or
"pipe" to indicate the type of a file and that field can be printed
directly
- ( ) An integer passed in as an address to the call is set to the
type of the file
- ( ) The kind is encoded in the `sb.st_mode' field of the struct and
macros are used to distinguish the kind and print an appropriate
message.
- ( ) The kind is encoded in the `sb.st_mode' field of the struct and
functions are used to distinguish the kind and print an appropriate
message.
Which one of the following is NOT a file "kind" reported by `stat() /
lstat()'
- ( ) Directory
- ( ) Binary
- ( ) Socket
- ( ) Symbolic Link (symlink)
mtime / ctime
~~~~~~~~~~~~~
Do some research and determine the difference between the `ctime' and
`mtime' fields that are reported by `stat() / lstat()'. Which of the
following best describes this difference:
- ( ) `mtime' and `ctime' actually always report the same time and
their redundancy is a historical oddity.
- ( ) `mtime' indicates the last time that the file was moved from one
directory to another while `ctime' indicates the last change to the
data in the file
- ( ) `mtime' is the last time of modification when data was altered
in the file while `ctime' is the last access time when data was read
from the file
- ( ) `mtime' is when the actual data of a file changes while `ctime'
is associated with permissions, links, or other meta data changes
associated with the file.
You can test your results for the above quiz questions via `make
test-quiz' after completing all quiz questions.
Additional Items to Observe
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The function `ctime()' and `strmode()' both use an interesting
technique to make it possible to easily produce a printable string for
situations like those in `filestats.c'. Time permitting, examine the
source code for `strmode()' in `strmode.c' and discuss with a TA how a
string is returned but there is no requirement to free that string.
Finally, like many system calls, `stat()' has a command-line
equivalent in the form of the `stat' command which prints to the
screen many of the statistics of a file and is useful at times.
,----
| >> stat A.txt
| File: A.txt
| Size: 2 Blocks: 8 IO Block: 4096 regular file
| Device: 254,1 Inode: 7080409 Links: 1
| Access: (0644/-rw-r--r--) Uid: ( 1000/kauffman) Gid: ( 985/ users)
| Access: 2024-11-07 14:15:55.332936076 -0500
| Modify: 2024-11-07 14:10:55.332925991 -0500
| Change: 2024-11-07 14:15:55.329602657 -0500
| Birth: 2024-11-06 16:43:41.436780892 -0500
`----
PROBLEM 2 CODE: newer_file.c Program
====================================
Fill in the template code provided in `newer_file.c'. The intent of
the program is to ensure that two named files exist and then compare
the modification time of them to print an older vs newer file. This
will require use of the `access()' and `stat()' system calls as well
as a `diff_timespec()' function that is provided in the template.
You can test your code `make test-code testnum=2'. Below is a
demonstration of how the complete program should work.
,----
| >> make newer_file # build
| gcc -Wall -Werror -g -Og -o newer_file newer_file.c
|
| >> ./newer_file
| Usage: ./newer_file <file1> <file2>
|
| >> echo A > A.txt # create 3 files
| >> echo B > B.txt
| >> echo C > C.txt # newest
| >> touch -d '-5min' A.txt # oldest
| >> touch -d '-3min' B.txt # middle
|
| >> ./newer_file A.txt B.txt
| A.txt is OLDER than B.txt
|
| >> ./newer_file C.txt B.txt
| C.txt is NEWER than B.txt
|
| >> ./newer_file C.txt C.txt
| C.txt and C.txt are EQUAL in age
|
| >> ./newer_file C.txt X.txt
| X.txt cannot be accessed
|
| >> ./newer_file Z.txt X.txt
| Both Z.txt and X.txt cannot be accessed
`----
4 Submission
Follow the instructions at the end of Lab01 if you need a refresher on how to upload your completed lab zip to Gradescope.