Project 2: swish - A Simple Command-Line Shell
Source
This project was adapted from CSCI 4061 Intro to Operating Systems at the University of Minnesota - Twin Cities [Fall 2024], taught by Jack Kolb.
π¦ Starter Code
You can download the starter code here: proj2-code.zip
Save the starter code under your csci4061 directory, which should now look like this:
csci4061/
βββ labs/
β βββ lab01-code/
β βββ ...
βββ projects/
βββ proj2-code/
β How to Succeed on This Project
- Read the specification thoroughly. Office hours help may be limited if you haven't.
- Understand every file in the starter code. Some helper functions will save you major time.
- Test independently. Our tests are not exhaustive; you must write and run manual tests.
- Expect to get stuck. Patience and methodical debugging are essential.
- Start early. Donβt wait until the deadline pressure mounts.
- Ask public questions on Piazza. It helps you and your classmates.
- Know the late policy. No submissions are accepted more than 48 hours late.
π§ Introduction
Whenever you open a terminal, you're interacting with a shell process. This project challenges you to implement a simplified shell called swish that can:
- Parse and execute user commands
- Support input/output redirection
- Handle signals like
SIGINT(Ctrl-C) andSIGTSTP(Ctrl-Z) - Manage foreground and background jobs
You will directly use system calls like fork(), execvp(), waitpid(), dup2(), and sigaction() to build swish from scratch, gaining a deep understanding of how Unix-like shells work internally.
π Skills You Will Develop
- String parsing using
strtok() - Process creation and management (
fork(),execvp(),waitpid()) - Input/output file redirection (
open(),dup2()) - Signal handling (
sigaction(),kill(),tcsetpgrp()) - Foreground/background job control
π» Makefile Commands
make # Compile swish
make clean # Remove compiled files
make clean-tests # Remove test outputs
make zip # Create Gradescope zip
make test # Run all test cases
make test testnum=5 # Run specific test
π§ͺ Manual Testing Advice
- Run
swishmanually outside of automated tests. - Simulate background jobs with
&. - Test input/output redirection with
>,>>,<. - Try Ctrl-C and Ctrl-Z to test signal handling.
- Use
jobs,fg,bg,wait-for,wait-allcommands interactively. - Debug issues using
gdb.
π§° Starter Code Files
| File | Purpose | Notes |
|---|---|---|
Makefile |
Build/tests | Do not modify |
string_vector.h / string_vector.c |
String token management | Do not modify |
job_list.h / job_list.c |
Job tracking linked list | Do not modify |
swish.c |
Main shell loop | EDIT THIS |
swish_funcs.h / swish_funcs.c |
Shell helper functions | EDIT THIS |
testius |
Test runner | Do not modify |
test_cases/ |
Sample inputs | Do not modify |
Only modify files marked as EDIT.
π Shell Features to Implement
Task 0: String Tokenization
- Complete
tokenize()function inswish_funcs.c. - Use
strtok()to split user input into individual tokens. - Populate a
strvec_tvector with the tokens.
Task 1: Working Directory Commands
- Implement
pwdcommand usinggetcwd(). - Implement
cdcommand usingchdir(), defaulting to$HOMEif no directory provided. - Print informative errors using
perror().
Task 2: Running External Commands
- In
main(),fork()a child process. - In child, call
run_command()toexecvp()the new program. - In parent, use
waitpid()to wait for child to terminate.
Task 3: Redirecting Input and Output
- Detect
<,>, and>>symbols in the tokens. - Redirect standard input/output to appropriate files using
open()anddup2(). - Ensure redirection tokens do not get passed to
execvp().
Task 4: Signal Management
- Use
setpgid()to separate child process groups. - Use
tcsetpgrp()to manage foreground process groups. - Use
sigaction()to reset signal handling for children.
Task 5: Managing Stopped Jobs
- Use
waitpid(WUNTRACED)to detect stopped processes. - Store stopped jobs in the
jobslist. - Implement the
fgcommand withresume_job().
Task 6: Running Background Jobs
- Detect
&at the end of user input. - Launch background jobs without calling
tcsetpgrp()orwaitpid()immediately. - Implement
bgto resume jobs in background. - Implement
wait-forandwait-allto clean up background jobs.
π§ Strategy & Hints
- Build incrementally. Test after every major feature.
- Handle errors explicitly. Always check system call return values.
- Reuse helper utilities.
string_vectorandjob_listare powerful. - Use proper memory cleanup. Avoid leaks when possible.
- Get comfortable with signals. Debugging signal issues is tricky but rewarding.
π Summary
Project 2 will give you firsthand experience building a working shell, combining string processing, system calls, signal handling, and job control. Youβll finish this project with a deep appreciation for systems programmingβand a real command-line tool you built from scratch!
Ready to begin? Download the starter code and start coding your own shell!