The first project is to build your own implementation of Busybox, which according to its website is the following:
BusyBox combines tiny versions of many common UNIX utilities into a single small executable. It provides replacements for most of the utilities you usually find in GNU fileutils, shellutils, etc.
You may think of Busybox as a complete Unix userland in a single binary
executable. Because of its compact size, it is found in many embedded
devices such as printers, network routers, and even some phones. In fact,
Alpine Linux, the official Linux distribution for Docker, uses
Busybox as its default userland rather than the traditional GNU
utilities found on most Linux machines. This means commands such as ls
and cat
are embedded inside of a single busybox
executable rather than
as separate programs.
Given the Busybox executable, busybox
, you can invoke any of its
internal commands (i.e. applets) by specifying the desired applet as the
first argument to the program:
$ busybox ls -l # Execute ls applet with the argument -l
Alteratively, you can symlink the busybox
executable to the name of any
applet and then execute the applet directly:
$ ln -s busybox ls # Create symbolic link from ls to busybox $ ./ls -l # Execute ls applet with the argument -l
Working in groups of one, two, or three people, you are to
utilize low-level system calls to create a your own version of Busybox
called idlebin
that supports multiple internal applets by midnight on
Friday, September 7, 2018. Additionally, your group is to present its
work to a teaching assistant by Friday, September 14, 2018.
More details about this project and your deliverables are described below.
By completing this project, you will achieve the following learning
goals:
Discover how basic Unix utilities implement core services by interacting with the operating system kernel via system calls.
Review using system calls in C99 (in particular those related to I/O, files, and directories) to perform systems programming.
Employ TDD as a development strategy by using tests for verification and by implementing your own unit tests.
For this project, you are to implement various Unix utilities as applets
in a single binary executable called idlebin
. Specifically, you must
implement clones of ls and cp as a group, and then later implement one
or two additional applets individually.
Working as a team, you are to utilize low-level-system calls to implement both ls and cp:
$ bin/idlebin ls --help # Display ls applet's usage message Usage: ls [-Ra] [PATHS]... -R List subdirectories recursively -a Do not ignore entries starting with . $ bin/idlebin cp --help # Display cp applet's usage message Usage: cp [-Rv] SOURCE... TARGET -R Copy directories recursively -v Explain what is being done
As with Busybox, your idlebin
applets only implement a subset of the
functionality (i.e. command-line options) of their traditional GNU
counterparts. For instance, your ls only needs to support the -R
and
-a
flags, which allow it to list subdirectories recursively or to display
all files, even those that begin with a .
.
To implement these applets, you will need to review and then utilize some of the following system calls and low-level functions: stat, open, read, write, close, readlink, symlink, opendir, readdir, closedir, scandir, and mkdir.
The behavior (in terms of operation and output) of your ls
and cp
applets must match that of both the GNU version and the reference
implementation provided below.
Each group applet is worth 6 Points each.
For ls
, consider how you would sort the command line arguments and
traverse an directory in sorted order.
For cp
, think carefully about all the different use cases (ie. copy
one file to a directory, copy multiple files to a directory, etc.) and how
you would detect these situations.
When possible create small helper functions that perform one specific action.
Develop your applets incrementally by supporting one feature or use case at a time.
Once your group has implemented both ls
and cp
and have passed all the
provided unit tests, you are then to work individually on one or two more
applets (use the same group repository, but each member must work on
different applets). Here is a table of possible applets to implement
individually:
Applet | Points |
---|---|
chmod OCTAL-MODE FILE... |
3.0 |
du -bc [FILE]... |
6.0 |
ln [-sv] TARGET LINK_NAME |
3.0 |
mkdir [-v] DIRECTORY... |
3.0 |
mv [-v] SOURCE ... DESTINATION |
6.0 |
realpath [-e] FILE... |
3.0 |
rm [-Rv] |
6.0 |
rmdir [-v] DIRECTORY... |
3.0 |
touch [FILES]... |
3.0 |
uname [-asnrvmo] |
3.0 |
Each individual member can earn up 6 Points (so either implement one applet worth 6 Points or two worth 3 Points).
Consult the appropriate manual pages and the GNU versions of the commands to determine the correct behavior and output your applet requires.
The work of each individual applet must go in a separate git branch
that can be later merged into the master
branch (ie. make a uname
branch if you are implementing that applet; only merge into master
once
you are complete).
To verify the correctness of your individual applet, you will need to write a [unit test] script in Python that provides a reasonable amount of test coverage for the features you implemented.
You can find a reference implementation of idlebin
in the following
location on AFS:
/afs/nd.edu/user15/pbui/pub/bin/idlebin
This will be updated periodically as more applets are written and added to the reference implementation.
As noted above, you are to work in groups of one or two (three
is permitted, but discouraged) to implement your idlebin
. You must use
(C99) (not C++) as the implementation language for idlebin
itself,
while the test scripts are to be written in Python.
Here is a timeline of events related to this project:
Date | Event |
---|---|
Sunday, August 19 | Project description and repository are available. |
Friday, September 7 | Code is due (pushed to GitLab to master branch). |
Friday, September 14 | Demonstration of idlebin must be completed. |
To start this project, one group member must fork the Project 01 repository on GitLab:
https://gitlab.com/nd-cse-30341-fa18/cse-30341-fa18-project01
Once this repository has been forked, follow the instructions from Reading 00 to:
Make the repository private.
Configure access to the repository.
Make sure you add all the members of the team in addition to the instructional staff.
As you can see, the base Project 01 repository contains a README.md
file and the following folder hierarchy:
project01 \_ Makefile # This is the project Makefile \_ bin # This contains the executable and symlinks \_ include # This contains the header files \_ src # This contains the C99 source code for idlebin executable \_ applets # This conatins the C99 source code for idlbein applets \_ tests # This contains the Python unit tests
You must maintain this folder structure for your project and place files in their appropriate place.
While the exact organization of the project code is up to you, keep in mind that you will be graded in part on coding style, cleaniness, and organization. This means your code should be consistently formatted, not contain any dead code, have reasonable comments, and appropriate naming among other things:
Break long functions into smaller functions.
Make sure each function does one thing and does it well.
Abstract, but don't over do it.
Please refer to these Coding Style slides for some tips and guidelines on coding style expectations.
To help you get started, we have provided a Makefile
that will build the
idlebin
application for you:
$ make # Build idlebin executable and create applet symlinks
Compiling src/applets/basename.o
Compiling src/applets/false.o
Compiling src/applets/pwd.o
Compiling src/applets/cat.o
Compiling src/applets/yes.o
Compiling src/applets/true.o
Linking bin/idlebin
Symlinking bin/basename
Symlinking bin/false
Symlinking bin/pwd
Symlinking bin/cat
Symlinking bin/yes
Symlinking bin/true
The provided Makefile
utilizes the GNU version of awk, aka. gawk.
On macOS, you will need to use Homebrew to install it if you don't have
it already.
Once you have the idlebin
executable, you can invoke the various applets
in the same way that you do with Busybox:
$ bin/idlebin # List all applets Usage: idlebin applet [ARGUMENTS]... Applets: basename false pwd cat yes true $ bin/idlebin pwd # Execute pwd applet /home/pbui/src/teaching/cse.30341.fa18/project01 $ bin/pwd # Execute pwd applet /home/pbui/src/teaching/cse.30341.fa18/project01 $ bin/pwd --help # Display pwd applet usage Usage: pwd
You can create additional applets to be embedded into idlebin
by placing
C99 source files in the src/applets
folder and defining at least the
following two items:
{APPLET}_USAGE
: This must be a const char
array that contains the
usage message for the new APPLET you are creating; it may consist of
multiple lines.
{APPLET}_applet
: This is a function that receives the command-line
arguments (int argc, char *argv[])
, performs the desired operations, and
then returns an int
corresponding to the applet's exit status.
Here is a simple template to follow:
/* {APPLET}.c: {APPLET} applet */ #include "idlebin.h" /* Usage */ const char {APPLET}_USAGE[] = "Usage: {APPLET}"; /* Applet */ int {APPLET}_applet(int argc, char *argv[]) { return EXIT_SUCCESS; }
The provided Makefile
will automatically detect any additional applets
placed in the src/applets
folder and will embed them into the idlebin
executable for you.
To verify the correctness of the applets in idlebin
, we have provided a
series of unit tests implemented in Python. These are located in the
tests
directory and can be executed all at once with the following
command:
$ make test # Run all test scripts Testing basename... test_00_help (test_basename.BasenameTestCase) ... ok test_01_usage (test_basename.BasenameTestCase) ... ok test_02_basename (test_basename.BasenameTestCase) ... ok ... ---------------------------------------------------------------------- Ran 81 tests in 17.488s FAILED (failures=25, errors=10) make: *** [Makefile:54: test] Error 1
Note, the first time you run make test
you will have failures since the
ls
and cp
applets have not been implemented yet.
You may execute all the unit tests of a specific command by running the test Python script directly:
$ ./tests/test_pwd.py -v # Run pwd test script Testing pwd... test_00_help (__main__.PwdTestCase) ... ok test_01_curdir (__main__.PwdTestCase) ... ok test_01_curdir_valgrind (__main__.PwdTestCase) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.570s OK
To add your own tests, simply create the corresponding test_{APPLET}.py
Python Script in the tests
folder. It is recommended that you model
your unit tests after the existing ones, which means utilizing Python's
unittest module for creating unit tests.
As part of your grade, you will need to present your idlebin
to a
teaching assistant where you will demonstrate the correctness of your
implementation along with answering any questions the TA may have.
This presentation should be no more than 15 minutes long and must be
scheduled ahead of time (we will provide a signup form soon).
As part of your demonstration, you must provide a Google Drive
presentation (between 5
- 10
slides) with the following content:
Design: Describe the overall design and organization of each of the
group applets (e.g. ls
and cp
); that is, explain what overall control
flow and logic along with how the various functions you created interact.
Implementation: Describe how a particular system call is used to implement a specific function in one of the group applets; explain exactly what happens in the user application and the operating system kernel for that corresponding code.
Testing: Identify a few tricky edge cases that you had to handle to correctly implement the group applets and explain how you addressed those challenges.
Summary: Described what you learned about operating systems and software development, and what you hope to improve upon in the future.
Note, you must incorporate images, graphs, diagrams and other visual elements as part of your presentation where reasonable.
Be prepared to be asked about different aspects of your project, as the TA may ask you questions to probe your understanding of the material and your work.
To arrange your demonstration time, please complete the form below:
As noted above, the Project 01 repository includes a README.md
file
with the following sections:
Members: This should be a list of the project members (names and email).
Demonstration: This is where you should provide a Google Drive link to your demonstration slides.
Applets: This contains the list of applets you are to implement.
You should check off any you completed (ie. [x]
) and include any notes
such as who implemented which applet and if there are any known issues or
bugs.
You must complete this document report as part of your project.
Once you have completed your project, you may do any of the following for individual extra credit:
You may implement up to two additional applets (or any of the commands found in Busybox's list of commands. You must pick a reasonable set of command-line arguments to support for each utility you implement. Each additional applet is worth 1 Point of extra credit and should be implemented in separate git branches.
You may borrow a [Raspberry Pi] from the instructor (or use your own), install a Linux distribution, and then compile, install, and run your idlebin on the [Raspberry Pi]. Accomplishing all of this would be worth 2 Points of extra credit.
To receive credit for either of these options, you must demonstrate your individual work after the group demonstrations.
Your project will be scored on the following metrics:
Metric | Points |
---|---|
Source Code
|
19.0
|
Demonstration
|
4.0
|
Documentation
|
1.0
|
In addition to meeting the functional requirements of the project (as described above), your program must not exhibit any memory leaks or invalid memory accesses as would be detected by Valgrind.
Additionally, because system calls can fail, your program must implement robust error handling and ensure your code checks the status of system calls when reasonable.
Moreover, you code must compile without any warnings (and -Wall
must
be one of the CFLAGS
).