From 9f8a7b6c89cceb3edebdff8e6775c20f48db12a1 Mon Sep 17 00:00:00 2001 From: TuDatTr Date: Mon, 1 Feb 2021 10:58:57 +0100 Subject: [PATCH] Initial commit --- Makefile | 88 +++++++++ README | 22 +++ myint.c | 36 ++++ myspin.c | 24 +++ mysplit.c | 35 ++++ mystop.c | 36 ++++ sdriver.pl | 210 ++++++++++++++++++++++ trace01.txt | 5 + trace02.txt | 5 + trace03.txt | 5 + trace04.txt | 5 + trace05.txt | 11 ++ trace06.txt | 8 + trace07.txt | 14 ++ trace08.txt | 14 ++ trace09.txt | 20 +++ trace10.txt | 22 +++ trace11.txt | 12 ++ trace12.txt | 17 ++ trace13.txt | 23 +++ trace14.txt | 47 +++++ trace15.txt | 46 +++++ tsh.c | 509 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tshref | Bin 0 -> 18976 bytes tshref.out | 220 +++++++++++++++++++++++ 25 files changed, 1434 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 myint.c create mode 100644 myspin.c create mode 100644 mysplit.c create mode 100644 mystop.c create mode 100755 sdriver.pl create mode 100644 trace01.txt create mode 100644 trace02.txt create mode 100644 trace03.txt create mode 100644 trace04.txt create mode 100644 trace05.txt create mode 100644 trace06.txt create mode 100644 trace07.txt create mode 100644 trace08.txt create mode 100644 trace09.txt create mode 100644 trace10.txt create mode 100644 trace11.txt create mode 100644 trace12.txt create mode 100644 trace13.txt create mode 100644 trace14.txt create mode 100644 trace15.txt create mode 100644 tsh.c create mode 100755 tshref create mode 100644 tshref.out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..447d132 --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +# Makefile for the CS:APP Shell Lab + +TEAM = NOBODY +VERSION = 1 +DRIVER = ./sdriver.pl +TSH = ./tsh +TSHREF = ./tshref +TSHARGS = "-p" +CC = gcc +CFLAGS = -Wall -O2 +FILES = $(TSH) ./myspin ./mysplit ./mystop ./myint + +all: $(FILES) + +################## +# Regression tests +################## + +# Run tests using the student's shell program +test01: + $(DRIVER) -t trace01.txt -s $(TSH) -a $(TSHARGS) +test02: + $(DRIVER) -t trace02.txt -s $(TSH) -a $(TSHARGS) +test03: + $(DRIVER) -t trace03.txt -s $(TSH) -a $(TSHARGS) +test04: + $(DRIVER) -t trace04.txt -s $(TSH) -a $(TSHARGS) +test05: + $(DRIVER) -t trace05.txt -s $(TSH) -a $(TSHARGS) +test06: + $(DRIVER) -t trace06.txt -s $(TSH) -a $(TSHARGS) +test07: + $(DRIVER) -t trace07.txt -s $(TSH) -a $(TSHARGS) +test08: + $(DRIVER) -t trace08.txt -s $(TSH) -a $(TSHARGS) +test09: + $(DRIVER) -t trace09.txt -s $(TSH) -a $(TSHARGS) +test10: + $(DRIVER) -t trace10.txt -s $(TSH) -a $(TSHARGS) +test11: + $(DRIVER) -t trace11.txt -s $(TSH) -a $(TSHARGS) +test12: + $(DRIVER) -t trace12.txt -s $(TSH) -a $(TSHARGS) +test13: + $(DRIVER) -t trace13.txt -s $(TSH) -a $(TSHARGS) +test14: + $(DRIVER) -t trace14.txt -s $(TSH) -a $(TSHARGS) +test15: + $(DRIVER) -t trace15.txt -s $(TSH) -a $(TSHARGS) + +# Run the tests using the reference shell program +rtest01: + $(DRIVER) -t trace01.txt -s $(TSHREF) -a $(TSHARGS) +rtest02: + $(DRIVER) -t trace02.txt -s $(TSHREF) -a $(TSHARGS) +rtest03: + $(DRIVER) -t trace03.txt -s $(TSHREF) -a $(TSHARGS) +rtest04: + $(DRIVER) -t trace04.txt -s $(TSHREF) -a $(TSHARGS) +rtest05: + $(DRIVER) -t trace05.txt -s $(TSHREF) -a $(TSHARGS) +rtest06: + $(DRIVER) -t trace06.txt -s $(TSHREF) -a $(TSHARGS) +rtest07: + $(DRIVER) -t trace07.txt -s $(TSHREF) -a $(TSHARGS) +rtest08: + $(DRIVER) -t trace08.txt -s $(TSHREF) -a $(TSHARGS) +rtest09: + $(DRIVER) -t trace09.txt -s $(TSHREF) -a $(TSHARGS) +rtest10: + $(DRIVER) -t trace10.txt -s $(TSHREF) -a $(TSHARGS) +rtest11: + $(DRIVER) -t trace11.txt -s $(TSHREF) -a $(TSHARGS) +rtest12: + $(DRIVER) -t trace12.txt -s $(TSHREF) -a $(TSHARGS) +rtest13: + $(DRIVER) -t trace13.txt -s $(TSHREF) -a $(TSHARGS) +rtest14: + $(DRIVER) -t trace14.txt -s $(TSHREF) -a $(TSHARGS) +rtest15: + $(DRIVER) -t trace15.txt -s $(TSHREF) -a $(TSHARGS) + + +# clean up +clean: + rm -f $(FILES) *.o *~ + + diff --git a/README b/README new file mode 100644 index 0000000..a5add38 --- /dev/null +++ b/README @@ -0,0 +1,22 @@ +################ +CS:APP Shell Lab +################ + +Files: + +Makefile # Compiles your shell program and runs the tests +README # This file +tsh.c # The shell program that you will write and hand in +tshref # The reference shell binary. + +# The remaining files are used to test your shell +sdriver.pl # The trace-driven shell driver +trace*.txt # The 15 trace files that control the shell driver +tshref.out # Example output of the reference shell on all 15 traces + +# Little C programs that are called by the trace files +myspin.c # Takes argument and spins for seconds +mysplit.c # Forks a child that spins for seconds +mystop.c # Spins for seconds and sends SIGTSTP to itself +myint.c # Spins for seconds and sends SIGINT to itself + diff --git a/myint.c b/myint.c new file mode 100644 index 0000000..ea5bee1 --- /dev/null +++ b/myint.c @@ -0,0 +1,36 @@ +/* + * myint.c - Another handy routine for testing your tiny shell + * + * usage: myint + * Sleeps for seconds and sends SIGINT to itself. + * + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int i, secs; + pid_t pid; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(0); + } + secs = atoi(argv[1]); + + for (i=0; i < secs; i++) + sleep(1); + + pid = getpid(); + + if (kill(pid, SIGINT) < 0) + fprintf(stderr, "kill (int) error"); + + exit(0); + +} diff --git a/myspin.c b/myspin.c new file mode 100644 index 0000000..08c3e0c --- /dev/null +++ b/myspin.c @@ -0,0 +1,24 @@ +/* + * myspin.c - A handy program for testing your tiny shell + * + * usage: myspin + * Sleeps for seconds in 1-second chunks. + * + */ +#include +#include +#include + +int main(int argc, char **argv) +{ + int i, secs; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(0); + } + secs = atoi(argv[1]); + for (i=0; i < secs; i++) + sleep(1); + exit(0); +} diff --git a/mysplit.c b/mysplit.c new file mode 100644 index 0000000..9ac016e --- /dev/null +++ b/mysplit.c @@ -0,0 +1,35 @@ +/* + * mysplit.c - Another handy routine for testing your tiny shell + * + * usage: mysplit + * Fork a child that spins for seconds in 1-second chunks. + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int i, secs; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(0); + } + secs = atoi(argv[1]); + + + if (fork() == 0) { /* child */ + for (i=0; i < secs; i++) + sleep(1); + exit(0); + } + + /* parent waits for child to terminate */ + wait(NULL); + + exit(0); +} diff --git a/mystop.c b/mystop.c new file mode 100644 index 0000000..12eee5f --- /dev/null +++ b/mystop.c @@ -0,0 +1,36 @@ +/* + * mystop.c - Another handy routine for testing your tiny shell + * + * usage: mystop + * Sleeps for seconds and sends SIGTSTP to itself. + * + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int i, secs; + pid_t pid; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(0); + } + secs = atoi(argv[1]); + + for (i=0; i < secs; i++) + sleep(1); + + pid = getpid(); + + if (kill(-pid, SIGTSTP) < 0) + fprintf(stderr, "kill (tstp) error"); + + exit(0); + +} diff --git a/sdriver.pl b/sdriver.pl new file mode 100755 index 0000000..852bf3d --- /dev/null +++ b/sdriver.pl @@ -0,0 +1,210 @@ +#!/usr/bin/perl +#!/usr/local/bin/perl +use Getopt::Std; +use FileHandle; +use IPC::Open2; + +####################################################################### +# sdriver.pl - Shell driver +# +# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. +# May not be used, modified, or copied without permission. +# +# The driver runs a student's shell program as a child, sends +# commands and signals to the child as directed by a trace file, +# and captures and displays the output produced by the child. +# +# Tracefile format: +# +# The tracefile consists of text lines that are either blank lines, +# comment lines, driver commands, or shell commands. Blank lines are +# ignored. Comment lines begin with "#" and are echo'd without change +# to stdout. Driver commands are intepreted by the driver and are not +# passed to the child shell. All other lines are shell commands and +# are passed without modification to the shell, which reads them on +# stdin. Output produced by the child on stdout/stderr is read by +# the parent and printed on its stdout. +# +# Driver commands: +# TSTP Send a SIGTSTP signal to the child +# INT Send a SIGINT signal to the child +# QUIT Send a SIGQUIT signal to the child +# KILL Send a SIGKILL signal to the child +# CLOSE Close Writer (sends EOF signal to child) +# WAIT Wait() for child to terminate +# SLEEP Sleep for seconds +# +###################################################################### + +# +# usage - print help message and terminate +# +sub usage +{ + printf STDERR "$_[0]\n"; + printf STDERR "Usage: $0 [-hv] -t -s -a \n"; + printf STDERR "Options:\n"; + printf STDERR " -h Print this message\n"; + printf STDERR " -v Be more verbose\n"; + printf STDERR " -t Trace file\n"; + printf STDERR " -s Shell program to test\n"; + printf STDERR " -a Shell arguments\n"; + printf STDERR " -g Generate output for autograder\n"; + die "\n" ; +} + +# Parse the command line arguments +getopts('hgvt:s:a:'); +if ($opt_h) { + usage(); +} +if (!$opt_t) { + usage("Missing required -t argument"); +} +if (!$opt_s) { + usage("Missing required -s argument"); +} +$verbose = $opt_v; +$infile = $opt_t; +$shellprog = $opt_s; +$shellargs = $opt_a; +$grade = $opt_g; + +# Make sure the input script exists and is readable +-e $infile + or die "$0: ERROR: $infile not found\n"; +-r $infile + or die "$0: ERROR: $infile is not readable\n"; + +# Make sure the shell program exists and is executable +-e $shellprog + or die "$0: ERROR: $shellprog not found\n"; +-x $shellprog + or die "$0: ERROR: $shellprog is not executable\n"; + + +# Open the input script +open INFILE, $infile + or die "$0: ERROR: Couldn't open input file $infile: $!\n"; + +# +# Fork a child, run the shell in it, and connect the parent +# and child with a pair of unidirectional pipes: +# parent:Writer -> child:stdin +# child:stdout -> parent:Reader +# +$pid = open2(\*Reader, \*Writer, "$shellprog $shellargs"); +Writer->autoflush(); + +# The autograder will want to know the child shell's pid +if ($grade) { + print ("pid=$pid\n"); +} + +# +# Parent reads a trace file, sends commands to the child shell. +# +while () { + $line = $_; + chomp($line); + + # Comment line + if ($line =~ /^#/) { + print "$line\n"; + } + + # Blank line + elsif ($line =~ /^\s*$/) { + if ($verbose) { + print "$0: Ignoring blank line\n"; + } + } + + # Send SIGTSTP (ctrl-z) + elsif ($line =~ /TSTP/) { + if ($verbose) { + print "$0: Sending SIGTSTP signal to process $pid\n"; + } + kill 'TSTP', $pid; + } + + # Send SIGINT (ctrl-c) + elsif ($line =~ /INT/) { + if ($verbose) { + print "$0: Sending SIGINT signal to process $pid\n"; + } + kill 'INT', $pid; + } + + # Send SIGQUIT (whenever we need graceful termination) + elsif ($line =~ /QUIT/) { + if ($verbose) { + print "$0: Sending SIGQUIT signal to process $pid\n"; + } + kill 'QUIT', $pid; + } + + # Send SIGKILL + elsif ($line =~ /KILL/) { + if ($verbose) { + print "$0: Sending SIGKILL signal to process $pid\n"; + } + kill 'KILL', $pid; + } + + # Close pipe (sends EOF notification to child) + elsif ($line =~ /CLOSE/) { + if ($verbose) { + print "$0: Closing output end of pipe to child $pid\n"; + } + close Writer; + } + + # Wait for child to terminate + elsif ($line =~ /WAIT/) { + if ($verbose) { + print "$0: Waiting for child $pid\n"; + } + wait; + if ($verbose) { + print "$0: Child $pid reaped\n"; + } + } + + # Sleep + elsif ($line =~ /SLEEP (\d+)/) { + if ($verbose) { + print "$0: Sleeping $1 secs\n"; + } + sleep $1; + } + + # Unknown input + else { + if ($verbose) { + print "$0: Sending :$line: to child $pid\n"; + } + print Writer "$line\n"; + } +} + +# +# Parent echoes the output produced by the child. +# +close Writer; +if ($verbose) { + print "$0: Reading data from child $pid\n"; +} +while ($line = ) { + print $line; +} +close Reader; + +# Finally, parent reaps child +wait; + +if ($verbose) { + print "$0: Shell terminated\n"; +} + +exit; diff --git a/trace01.txt b/trace01.txt new file mode 100644 index 0000000..9c8561e --- /dev/null +++ b/trace01.txt @@ -0,0 +1,5 @@ +# +# trace01.txt - Properly terminate on EOF. +# +CLOSE +WAIT diff --git a/trace02.txt b/trace02.txt new file mode 100644 index 0000000..e97643b --- /dev/null +++ b/trace02.txt @@ -0,0 +1,5 @@ +# +# trace02.txt - Process builtin quit command. +# +quit +WAIT diff --git a/trace03.txt b/trace03.txt new file mode 100644 index 0000000..be8869c --- /dev/null +++ b/trace03.txt @@ -0,0 +1,5 @@ +# +# trace03.txt - Run a foreground job. +# +/bin/echo tsh> quit +quit diff --git a/trace04.txt b/trace04.txt new file mode 100644 index 0000000..554df0e --- /dev/null +++ b/trace04.txt @@ -0,0 +1,5 @@ +# +# trace04.txt - Run a background job. +# +/bin/echo -e tsh> ./myspin 1 \046 +./myspin 1 & diff --git a/trace05.txt b/trace05.txt new file mode 100644 index 0000000..03c1876 --- /dev/null +++ b/trace05.txt @@ -0,0 +1,11 @@ +# +# trace05.txt - Process jobs builtin command. +# +/bin/echo -e tsh> ./myspin 2 \046 +./myspin 2 & + +/bin/echo -e tsh> ./myspin 3 \046 +./myspin 3 & + +/bin/echo tsh> jobs +jobs diff --git a/trace06.txt b/trace06.txt new file mode 100644 index 0000000..bfa3890 --- /dev/null +++ b/trace06.txt @@ -0,0 +1,8 @@ +# +# trace06.txt - Forward SIGINT to foreground job. +# +/bin/echo -e tsh> ./myspin 4 +./myspin 4 + +SLEEP 2 +INT diff --git a/trace07.txt b/trace07.txt new file mode 100644 index 0000000..259a285 --- /dev/null +++ b/trace07.txt @@ -0,0 +1,14 @@ +# +# trace07.txt - Forward SIGINT only to foreground job. +# +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +/bin/echo -e tsh> ./myspin 5 +./myspin 5 + +SLEEP 2 +INT + +/bin/echo tsh> jobs +jobs diff --git a/trace08.txt b/trace08.txt new file mode 100644 index 0000000..49be19f --- /dev/null +++ b/trace08.txt @@ -0,0 +1,14 @@ +# +# trace08.txt - Forward SIGTSTP only to foreground job. +# +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +/bin/echo -e tsh> ./myspin 5 +./myspin 5 + +SLEEP 2 +TSTP + +/bin/echo tsh> jobs +jobs diff --git a/trace09.txt b/trace09.txt new file mode 100644 index 0000000..340d998 --- /dev/null +++ b/trace09.txt @@ -0,0 +1,20 @@ +# +# trace09.txt - Process bg builtin command +# +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +/bin/echo -e tsh> ./myspin 5 +./myspin 5 + +SLEEP 2 +TSTP + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> bg %2 +bg %2 + +/bin/echo tsh> jobs +jobs diff --git a/trace10.txt b/trace10.txt new file mode 100644 index 0000000..e7de996 --- /dev/null +++ b/trace10.txt @@ -0,0 +1,22 @@ +# +# trace10.txt - Process fg builtin command. +# +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +SLEEP 1 +/bin/echo tsh> fg %1 +fg %1 + +SLEEP 1 +TSTP + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> fg %1 +fg %1 + +/bin/echo tsh> jobs +jobs + diff --git a/trace11.txt b/trace11.txt new file mode 100644 index 0000000..d2f8663 --- /dev/null +++ b/trace11.txt @@ -0,0 +1,12 @@ +# +# trace11.txt - Forward SIGINT to every process in foreground process group +# +/bin/echo -e tsh> ./mysplit 4 +./mysplit 4 + +SLEEP 2 +INT + +/bin/echo tsh> /bin/ps a +/bin/ps a + diff --git a/trace12.txt b/trace12.txt new file mode 100644 index 0000000..88455e3 --- /dev/null +++ b/trace12.txt @@ -0,0 +1,17 @@ +# +# trace12.txt - Forward SIGTSTP to every process in foreground process group +# +/bin/echo -e tsh> ./mysplit 4 +./mysplit 4 + +SLEEP 2 +TSTP + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> /bin/ps a +/bin/ps a + + + diff --git a/trace13.txt b/trace13.txt new file mode 100644 index 0000000..d734cbc --- /dev/null +++ b/trace13.txt @@ -0,0 +1,23 @@ +# +# trace13.txt - Restart every stopped process in process group +# +/bin/echo -e tsh> ./mysplit 4 +./mysplit 4 + +SLEEP 2 +TSTP + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> /bin/ps a +/bin/ps a + +/bin/echo tsh> fg %1 +fg %1 + +/bin/echo tsh> /bin/ps a +/bin/ps a + + + diff --git a/trace14.txt b/trace14.txt new file mode 100644 index 0000000..8086580 --- /dev/null +++ b/trace14.txt @@ -0,0 +1,47 @@ +# +# trace14.txt - Simple error handling +# +/bin/echo tsh> ./bogus +./bogus + +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +/bin/echo tsh> fg +fg + +/bin/echo tsh> bg +bg + +/bin/echo tsh> fg a +fg a + +/bin/echo tsh> bg a +bg a + +/bin/echo tsh> fg 9999999 +fg 9999999 + +/bin/echo tsh> bg 9999999 +bg 9999999 + +/bin/echo tsh> fg %2 +fg %2 + +/bin/echo tsh> fg %1 +fg %1 + +SLEEP 2 +TSTP + +/bin/echo tsh> bg %2 +bg %2 + +/bin/echo tsh> bg %1 +bg %1 + +/bin/echo tsh> jobs +jobs + + + diff --git a/trace15.txt b/trace15.txt new file mode 100644 index 0000000..2cc780e --- /dev/null +++ b/trace15.txt @@ -0,0 +1,46 @@ +# +# trace15.txt - Putting it all together +# + +/bin/echo tsh> ./bogus +./bogus + +/bin/echo tsh> ./myspin 10 +./myspin 10 + +SLEEP 2 +INT + +/bin/echo -e tsh> ./myspin 3 \046 +./myspin 3 & + +/bin/echo -e tsh> ./myspin 4 \046 +./myspin 4 & + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> fg %1 +fg %1 + +SLEEP 2 +TSTP + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> bg %3 +bg %3 + +/bin/echo tsh> bg %1 +bg %1 + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> fg %1 +fg %1 + +/bin/echo tsh> quit +quit + diff --git a/tsh.c b/tsh.c new file mode 100644 index 0000000..4e39200 --- /dev/null +++ b/tsh.c @@ -0,0 +1,509 @@ +/* + * tsh - A tiny shell program with job control + * + * Schlittenhardt, Anna und Tran,Tuan-Dat + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Misc manifest constants */ +#define MAXLINE 1024 /* max line size */ +#define MAXARGS 128 /* max args on a command line */ +#define MAXJOBS 16 /* max jobs at any point in time */ +#define MAXJID 1<<16 /* max job ID */ + +/* Job states */ +#define UNDEF 0 /* undefined */ +#define FG 1 /* running in foreground */ +#define BG 2 /* running in background */ +#define ST 3 /* stopped */ + +/* + * Jobs states: FG (foreground), BG (background), ST (stopped) + * Job state transitions and enabling actions: + * FG -> ST : ctrl-z + * ST -> FG : fg command + * ST -> BG : bg command + * BG -> FG : fg command + * At most 1 job can be in the FG state. + */ + +/* Global variables */ +extern char **environ; /* defined in libc */ +char prompt[] = "tsh> "; /* command line prompt (DO NOT CHANGE) */ +int verbose = 0; /* if true, print additional output */ +int nextjid = 1; /* next job ID to allocate */ +char sbuf[MAXLINE]; /* for composing sprintf messages */ + +struct job_t { /* The job struct */ + pid_t pid; /* job PID */ + int jid; /* job ID [1, 2, ...] */ + int state; /* UNDEF, BG, FG, or ST */ + char cmdline[MAXLINE]; /* command line */ +}; +struct job_t jobs[MAXJOBS]; /* The job list */ +/* End global variables */ + + +/* Function prototypes */ + +/* Here are the functions that you will implement */ +void eval(char *cmdline); +int builtin_cmd(char **argv); +void do_bgfg(char **argv); +void waitfg(pid_t pid); + +void sigchld_handler(int sig); +void sigtstp_handler(int sig); +void sigint_handler(int sig); + +/* Here are helper routines that we've provided for you */ +int parseline(const char *cmdline, char **argv); +void sigquit_handler(int sig); + +void clearjob(struct job_t *job); +void initjobs(struct job_t *jobs); +int maxjid(struct job_t *jobs); +int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline); +int deletejob(struct job_t *jobs, pid_t pid); +pid_t fgpid(struct job_t *jobs); +struct job_t *getjobpid(struct job_t *jobs, pid_t pid); +struct job_t *getjobjid(struct job_t *jobs, int jid); +int pid2jid(pid_t pid); +void listjobs(struct job_t *jobs); + +void usage(void); +void unix_error(char *msg); +void app_error(char *msg); +typedef void handler_t(int); +handler_t *Signal(int signum, handler_t *handler); + +/* + * main - The shell's main routine + */ +int main(int argc, char **argv) +{ + char c; + char cmdline[MAXLINE]; + int emit_prompt = 1; /* emit prompt (default) */ + + /* Redirect stderr to stdout (so that driver will get all output + * on the pipe connected to stdout) */ + dup2(1, 2); + + /* Parse the command line */ + while ((c = getopt(argc, argv, "hvp")) != EOF) { + switch (c) { + case 'h': /* print help message */ + usage(); + break; + case 'v': /* emit additional diagnostic info */ + verbose = 1; + break; + case 'p': /* don't print a prompt */ + emit_prompt = 0; /* handy for automatic testing */ + break; + default: + usage(); + } + } + + /* Install the signal handlers */ + + /* These are the ones you will need to implement */ + Signal(SIGINT, sigint_handler); /* ctrl-c */ + Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */ + Signal(SIGCHLD, sigchld_handler); /* Terminated or stopped child */ + + /* This one provides a clean way to kill the shell */ + Signal(SIGQUIT, sigquit_handler); + + /* Initialize the job list */ + initjobs(jobs); + + /* Execute the shell's read/eval loop */ + while (1) { + + /* Read command line */ + if (emit_prompt) { + printf("%s", prompt); + fflush(stdout); + } + if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin)) + app_error("fgets error"); + if (feof(stdin)) { /* End of file (ctrl-d) */ + fflush(stdout); + exit(0); + } + + /* Evaluate the command line */ + eval(cmdline); + fflush(stdout); + fflush(stdout); + } + + exit(0); /* control never reaches here */ +} + +/* + * eval - Evaluate the command line that the user has just typed in + * + * If the user has requested a built-in command (quit, jobs, bg or fg) + * then execute it immediately. Otherwise, fork a child process and + * run the job in the context of the child. If the job is running in + * the foreground, wait for it to terminate and then return. Note: + * each child process must have a unique process group ID so that our + * background children don't receive SIGINT (SIGTSTP) from the kernel + * when we type ctrl-c (ctrl-z) at the keyboard. +*/ +void eval(char *cmdline) +{ + return; +} + +/* + * parseline - Parse the command line and build the argv array. + * + * Characters enclosed in single quotes are treated as a single + * argument. Return true if the user has requested a BG job, false if + * the user has requested a FG job. + */ +int parseline(const char *cmdline, char **argv) +{ + static char array[MAXLINE]; /* holds local copy of command line */ + char *buf = array; /* ptr that traverses command line */ + char *delim; /* points to first space delimiter */ + int argc; /* number of args */ + int bg; /* background job? */ + + strcpy(buf, cmdline); + buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */ + while (*buf && (*buf == ' ')) /* ignore leading spaces */ + buf++; + + /* Build the argv list */ + argc = 0; + if (*buf == '\'') { + buf++; + delim = strchr(buf, '\''); + } + else { + delim = strchr(buf, ' '); + } + + while (delim) { + argv[argc++] = buf; + *delim = '\0'; + buf = delim + 1; + while (*buf && (*buf == ' ')) /* ignore spaces */ + buf++; + + if (*buf == '\'') { + buf++; + delim = strchr(buf, '\''); + } + else { + delim = strchr(buf, ' '); + } + } + argv[argc] = NULL; + + if (argc == 0) /* ignore blank line */ + return 1; + + /* should the job run in the background? */ + if ((bg = (*argv[argc-1] == '&')) != 0) { + argv[--argc] = NULL; + } + return bg; +} + +/* + * builtin_cmd - If the user has typed a built-in command then execute + * it immediately. + */ +int builtin_cmd(char **argv) +{ + return 0; /* not a builtin command */ +} + +/* + * do_bgfg - Execute the builtin bg and fg commands + */ +void do_bgfg(char **argv) +{ + return; +} + +/* + * waitfg - Block until process pid is no longer the foreground process + */ +void waitfg(pid_t pid) +{ + return; +} + +/***************** + * Signal handlers + *****************/ + +/* + * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever + * a child job terminates (becomes a zombie), or stops because it + * received a SIGSTOP or SIGTSTP signal. The handler reaps all + * available zombie children, but doesn't wait for any other + * currently running children to terminate. + */ +void sigchld_handler(int sig) +{ + return; +} + +/* + * sigint_handler - The kernel sends a SIGINT to the shell whenver the + * user types ctrl-c at the keyboard. Catch it and send it along + * to the foreground job. + */ +void sigint_handler(int sig) +{ + return; +} + +/* + * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever + * the user types ctrl-z at the keyboard. Catch it and suspend the + * foreground job by sending it a SIGTSTP. + */ +void sigtstp_handler(int sig) +{ + return; +} + +/********************* + * End signal handlers + *********************/ + +/*********************************************** + * Helper routines that manipulate the job list + **********************************************/ + +/* clearjob - Clear the entries in a job struct */ +void clearjob(struct job_t *job) { + job->pid = 0; + job->jid = 0; + job->state = UNDEF; + job->cmdline[0] = '\0'; +} + +/* initjobs - Initialize the job list */ +void initjobs(struct job_t *jobs) { + int i; + + for (i = 0; i < MAXJOBS; i++) + clearjob(&jobs[i]); +} + +/* maxjid - Returns largest allocated job ID */ +int maxjid(struct job_t *jobs) +{ + int i, max=0; + + for (i = 0; i < MAXJOBS; i++) + if (jobs[i].jid > max) + max = jobs[i].jid; + return max; +} + +/* addjob - Add a job to the job list */ +int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline) +{ + int i; + + if (pid < 1) + return 0; + + for (i = 0; i < MAXJOBS; i++) { + if (jobs[i].pid == 0) { + jobs[i].pid = pid; + jobs[i].state = state; + jobs[i].jid = nextjid++; + if (nextjid > MAXJOBS) + nextjid = 1; + strcpy(jobs[i].cmdline, cmdline); + if(verbose){ + printf("Added job [%d] %d %s\n", jobs[i].jid, jobs[i].pid, jobs[i].cmdline); + } + return 1; + } + } + printf("Tried to create too many jobs\n"); + return 0; +} + +/* deletejob - Delete a job whose PID=pid from the job list */ +int deletejob(struct job_t *jobs, pid_t pid) +{ + int i; + + if (pid < 1) + return 0; + + for (i = 0; i < MAXJOBS; i++) { + if (jobs[i].pid == pid) { + clearjob(&jobs[i]); + nextjid = maxjid(jobs)+1; + return 1; + } + } + return 0; +} + +/* fgpid - Return PID of current foreground job, 0 if no such job */ +pid_t fgpid(struct job_t *jobs) { + int i; + + for (i = 0; i < MAXJOBS; i++) + if (jobs[i].state == FG) + return jobs[i].pid; + return 0; +} + +/* getjobpid - Find a job (by PID) on the job list */ +struct job_t *getjobpid(struct job_t *jobs, pid_t pid) { + int i; + + if (pid < 1) + return NULL; + for (i = 0; i < MAXJOBS; i++) + if (jobs[i].pid == pid) + return &jobs[i]; + return NULL; +} + +/* getjobjid - Find a job (by JID) on the job list */ +struct job_t *getjobjid(struct job_t *jobs, int jid) +{ + int i; + + if (jid < 1) + return NULL; + for (i = 0; i < MAXJOBS; i++) + if (jobs[i].jid == jid) + return &jobs[i]; + return NULL; +} + +/* pid2jid - Map process ID to job ID */ +int pid2jid(pid_t pid) +{ + int i; + + if (pid < 1) + return 0; + for (i = 0; i < MAXJOBS; i++) + if (jobs[i].pid == pid) { + return jobs[i].jid; + } + return 0; +} + +/* listjobs - Print the job list */ +void listjobs(struct job_t *jobs) +{ + int i; + + for (i = 0; i < MAXJOBS; i++) { + if (jobs[i].pid != 0) { + printf("[%d] (%d) ", jobs[i].jid, jobs[i].pid); + switch (jobs[i].state) { + case BG: + printf("Running "); + break; + case FG: + printf("Foreground "); + break; + case ST: + printf("Stopped "); + break; + default: + printf("listjobs: Internal error: job[%d].state=%d ", + i, jobs[i].state); + } + printf("%s", jobs[i].cmdline); + } + } +} +/****************************** + * end job list helper routines + ******************************/ + + +/*********************** + * Other helper routines + ***********************/ + +/* + * usage - print a help message + */ +void usage(void) +{ + printf("Usage: shell [-hvp]\n"); + printf(" -h print this message\n"); + printf(" -v print additional diagnostic information\n"); + printf(" -p do not emit a command prompt\n"); + exit(1); +} + +/* + * unix_error - unix-style error routine + */ +void unix_error(char *msg) +{ + fprintf(stdout, "%s: %s\n", msg, strerror(errno)); + exit(1); +} + +/* + * app_error - application-style error routine + */ +void app_error(char *msg) +{ + fprintf(stdout, "%s\n", msg); + exit(1); +} + +/* + * Signal - wrapper for the sigaction function + */ +handler_t *Signal(int signum, handler_t *handler) +{ + struct sigaction action, old_action; + + action.sa_handler = handler; + sigemptyset(&action.sa_mask); /* block sigs of type being handled */ + action.sa_flags = SA_RESTART; /* restart syscalls if possible */ + + if (sigaction(signum, &action, &old_action) < 0) + unix_error("Signal error"); + return (old_action.sa_handler); +} + +/* + * sigquit_handler - The driver program can gracefully terminate the + * child shell by sending it a SIGQUIT signal. + */ +void sigquit_handler(int sig) +{ + printf("Terminating after receipt of SIGQUIT signal\n"); + exit(1); +} + + + diff --git a/tshref b/tshref new file mode 100755 index 0000000000000000000000000000000000000000..eae17f8b0480538d2966affb6e6369d263edb8de GIT binary patch literal 18976 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 InqB{Y08ko+S^xk5 literal 0 HcmV?d00001 diff --git a/tshref.out b/tshref.out new file mode 100644 index 0000000..9093559 --- /dev/null +++ b/tshref.out @@ -0,0 +1,220 @@ +make[1]: Entering directory `/afs/cs.cmu.edu/project/ics/im/labs/shlab/src' +./sdriver.pl -t trace01.txt -s ./tsh -a "-p" +# +# trace01.txt - Properly terminate on EOF. +# +./sdriver.pl -t trace02.txt -s ./tsh -a "-p" +# +# trace02.txt - Process builtin quit command. +# +./sdriver.pl -t trace03.txt -s ./tsh -a "-p" +# +# trace03.txt - Run a foreground job. +# +tsh> quit +./sdriver.pl -t trace04.txt -s ./tsh -a "-p" +# +# trace04.txt - Run a background job. +# +tsh> ./myspin 1 & +[1] (26252) ./myspin 1 & +./sdriver.pl -t trace05.txt -s ./tsh -a "-p" +# +# trace05.txt - Process jobs builtin command. +# +tsh> ./myspin 2 & +[1] (26256) ./myspin 2 & +tsh> ./myspin 3 & +[2] (26258) ./myspin 3 & +tsh> jobs +[1] (26256) Running ./myspin 2 & +[2] (26258) Running ./myspin 3 & +./sdriver.pl -t trace06.txt -s ./tsh -a "-p" +# +# trace06.txt - Forward SIGINT to foreground job. +# +tsh> ./myspin 4 +Job [1] (26263) terminated by signal 2 +./sdriver.pl -t trace07.txt -s ./tsh -a "-p" +# +# trace07.txt - Forward SIGINT only to foreground job. +# +tsh> ./myspin 4 & +[1] (26267) ./myspin 4 & +tsh> ./myspin 5 +Job [2] (26269) terminated by signal 2 +tsh> jobs +[1] (26267) Running ./myspin 4 & +./sdriver.pl -t trace08.txt -s ./tsh -a "-p" +# +# trace08.txt - Forward SIGTSTP only to foreground job. +# +tsh> ./myspin 4 & +[1] (26274) ./myspin 4 & +tsh> ./myspin 5 +Job [2] (26276) stopped by signal 20 +tsh> jobs +[1] (26274) Running ./myspin 4 & +[2] (26276) Stopped ./myspin 5 +./sdriver.pl -t trace09.txt -s ./tsh -a "-p" +# +# trace09.txt - Process bg builtin command +# +tsh> ./myspin 4 & +[1] (26281) ./myspin 4 & +tsh> ./myspin 5 +Job [2] (26283) stopped by signal 20 +tsh> jobs +[1] (26281) Running ./myspin 4 & +[2] (26283) Stopped ./myspin 5 +tsh> bg %2 +[2] (26283) ./myspin 5 +tsh> jobs +[1] (26281) Running ./myspin 4 & +[2] (26283) Running ./myspin 5 +./sdriver.pl -t trace10.txt -s ./tsh -a "-p" +# +# trace10.txt - Process fg builtin command. +# +tsh> ./myspin 4 & +[1] (26290) ./myspin 4 & +tsh> fg %1 +Job [1] (26290) stopped by signal 20 +tsh> jobs +[1] (26290) Stopped ./myspin 4 & +tsh> fg %1 +tsh> jobs +./sdriver.pl -t trace11.txt -s ./tsh -a "-p" +# +# trace11.txt - Forward SIGINT to every process in foreground process group +# +tsh> ./mysplit 4 +Job [1] (26298) terminated by signal 2 +tsh> /bin/ps a + PID TTY STAT TIME COMMAND +25181 pts/3 S 0:00 -usr/local/bin/tcsh -i +26239 pts/3 S 0:00 make tshrefout +26240 pts/3 S 0:00 /bin/sh -c make tests > tshref.out 2>&1 +26241 pts/3 S 0:00 make tests +26295 pts/3 S 0:00 perl ./sdriver.pl -t trace11.txt -s ./tsh -a -p +26296 pts/3 S 0:00 ./tsh -p +26301 pts/3 R 0:00 /bin/ps a +./sdriver.pl -t trace12.txt -s ./tsh -a "-p" +# +# trace12.txt - Forward SIGTSTP to every process in foreground process group +# +tsh> ./mysplit 4 +Job [1] (26305) stopped by signal 20 +tsh> jobs +[1] (26305) Stopped ./mysplit 4 +tsh> /bin/ps a + PID TTY STAT TIME COMMAND +25181 pts/3 S 0:00 -usr/local/bin/tcsh -i +26239 pts/3 S 0:00 make tshrefout +26240 pts/3 S 0:00 /bin/sh -c make tests > tshref.out 2>&1 +26241 pts/3 S 0:00 make tests +26302 pts/3 S 0:00 perl ./sdriver.pl -t trace12.txt -s ./tsh -a -p +26303 pts/3 S 0:00 ./tsh -p +26305 pts/3 T 0:00 ./mysplit 4 +26306 pts/3 T 0:00 ./mysplit 4 +26309 pts/3 R 0:00 /bin/ps a +./sdriver.pl -t trace13.txt -s ./tsh -a "-p" +# +# trace13.txt - Restart every stopped process in process group +# +tsh> ./mysplit 4 +Job [1] (26313) stopped by signal 20 +tsh> jobs +[1] (26313) Stopped ./mysplit 4 +tsh> /bin/ps a + PID TTY STAT TIME COMMAND +25181 pts/3 S 0:00 -usr/local/bin/tcsh -i +26239 pts/3 S 0:00 make tshrefout +26240 pts/3 S 0:00 /bin/sh -c make tests > tshref.out 2>&1 +26241 pts/3 S 0:00 make tests +26310 pts/3 S 0:00 perl ./sdriver.pl -t trace13.txt -s ./tsh -a -p +26311 pts/3 S 0:00 ./tsh -p +26313 pts/3 T 0:00 ./mysplit 4 +26314 pts/3 T 0:00 ./mysplit 4 +26317 pts/3 R 0:00 /bin/ps a +tsh> fg %1 +tsh> /bin/ps a + PID TTY STAT TIME COMMAND +25181 pts/3 S 0:00 -usr/local/bin/tcsh -i +26239 pts/3 S 0:00 make tshrefout +26240 pts/3 S 0:00 /bin/sh -c make tests > tshref.out 2>&1 +26241 pts/3 S 0:00 make tests +26310 pts/3 S 0:00 perl ./sdriver.pl -t trace13.txt -s ./tsh -a -p +26311 pts/3 S 0:00 ./tsh -p +26320 pts/3 R 0:00 /bin/ps a +./sdriver.pl -t trace14.txt -s ./tsh -a "-p" +# +# trace14.txt - Simple error handling +# +tsh> ./bogus +./bogus: Command not found +tsh> ./myspin 4 & +[1] (26326) ./myspin 4 & +tsh> fg +fg command requires PID or %jobid argument +tsh> bg +bg command requires PID or %jobid argument +tsh> fg a +fg: argument must be a PID or %jobid +tsh> bg a +bg: argument must be a PID or %jobid +tsh> fg 9999999 +(9999999): No such process +tsh> bg 9999999 +(9999999): No such process +tsh> fg %2 +%2: No such job +tsh> fg %1 +Job [1] (26326) stopped by signal 20 +tsh> bg %2 +%2: No such job +tsh> bg %1 +[1] (26326) ./myspin 4 & +tsh> jobs +[1] (26326) Running ./myspin 4 & +./sdriver.pl -t trace15.txt -s ./tsh -a "-p" +# +# trace15.txt - Putting it all together +# +tsh> ./bogus +./bogus: Command not found +tsh> ./myspin 10 +Job [1] (26343) terminated by signal 2 +tsh> ./myspin 3 & +[1] (26345) ./myspin 3 & +tsh> ./myspin 4 & +[2] (26347) ./myspin 4 & +tsh> jobs +[1] (26345) Running ./myspin 3 & +[2] (26347) Running ./myspin 4 & +tsh> fg %1 +Job [1] (26345) stopped by signal 20 +tsh> jobs +[1] (26345) Stopped ./myspin 3 & +[2] (26347) Running ./myspin 4 & +tsh> bg %3 +%3: No such job +tsh> bg %1 +[1] (26345) ./myspin 3 & +tsh> jobs +[1] (26345) Running ./myspin 3 & +[2] (26347) Running ./myspin 4 & +tsh> fg %1 +tsh> quit +./sdriver.pl -t trace16.txt -s ./tsh -a "-p" +# +# trace16.txt - Tests whether the shell can handle SIGTSTP and SIGINT +# signals that come from other processes instead of the terminal. +# +tsh> ./mystop 2 +Job [1] (26359) stopped by signal 20 +tsh> jobs +[1] (26359) Stopped ./mystop 2 +tsh> ./myint 2 +Job [2] (26362) terminated by signal 2 +make[1]: Leaving directory `/afs/cs.cmu.edu/project/ics/im/labs/shlab/src'