From e2a5e6750a362e0fd8c89f3d1d40a623ba6d1fd6 Mon Sep 17 00:00:00 2001 From: Woong Sul Date: Wed, 12 Nov 2025 02:58:26 +0000 Subject: [PATCH] Lab03 assigned --- 03_shlab/Makefile | 93 ++++++++ 03_shlab/README | 22 ++ 03_shlab/myint.c | 36 +++ 03_shlab/myspin.c | 24 ++ 03_shlab/mysplit.c | 35 +++ 03_shlab/mystop.c | 36 +++ 03_shlab/sdriver.pl | 210 ++++++++++++++++++ 03_shlab/trace01.txt | 5 + 03_shlab/trace02.txt | 5 + 03_shlab/trace03.txt | 5 + 03_shlab/trace04.txt | 5 + 03_shlab/trace05.txt | 11 + 03_shlab/trace06.txt | 8 + 03_shlab/trace07.txt | 14 ++ 03_shlab/trace08.txt | 14 ++ 03_shlab/trace09.txt | 20 ++ 03_shlab/trace10.txt | 22 ++ 03_shlab/trace11.txt | 12 + 03_shlab/trace12.txt | 17 ++ 03_shlab/trace13.txt | 23 ++ 03_shlab/trace14.txt | 47 ++++ 03_shlab/trace15.txt | 46 ++++ 03_shlab/trace16.txt | 16 ++ 03_shlab/tsh.c | 516 +++++++++++++++++++++++++++++++++++++++++++ 03_shlab/tshref | Bin 0 -> 19278 bytes 03_shlab/tshref.out | 218 ++++++++++++++++++ 26 files changed, 1460 insertions(+) create mode 100644 03_shlab/Makefile create mode 100644 03_shlab/README create mode 100644 03_shlab/myint.c create mode 100644 03_shlab/myspin.c create mode 100644 03_shlab/mysplit.c create mode 100644 03_shlab/mystop.c create mode 100755 03_shlab/sdriver.pl create mode 100644 03_shlab/trace01.txt create mode 100644 03_shlab/trace02.txt create mode 100644 03_shlab/trace03.txt create mode 100644 03_shlab/trace04.txt create mode 100644 03_shlab/trace05.txt create mode 100644 03_shlab/trace06.txt create mode 100644 03_shlab/trace07.txt create mode 100644 03_shlab/trace08.txt create mode 100644 03_shlab/trace09.txt create mode 100644 03_shlab/trace10.txt create mode 100644 03_shlab/trace11.txt create mode 100644 03_shlab/trace12.txt create mode 100644 03_shlab/trace13.txt create mode 100644 03_shlab/trace14.txt create mode 100644 03_shlab/trace15.txt create mode 100644 03_shlab/trace16.txt create mode 100644 03_shlab/tsh.c create mode 100755 03_shlab/tshref create mode 100644 03_shlab/tshref.out diff --git a/03_shlab/Makefile b/03_shlab/Makefile new file mode 100644 index 0000000..f1b5762 --- /dev/null +++ b/03_shlab/Makefile @@ -0,0 +1,93 @@ +# Makefile for the Shell Lab + +TEAM = INDIVIDUAL +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 +################## + +tests: test01 test02 test03 test04 test05 test06 test07 test08 test09 test10 test11 test12 test13 test14 test15 test16 +# 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) +test16: + $(DRIVER) -t trace16.txt -s $(TSH) -a $(TSHARGS) + +rtests: rtest01 rtest02 rtest03 rtest04 rtest05 rtest06 rtest07 rtest08 rtest09 rtest10 rtest11 rtest12 rtest13 rtest14 rtest15 rtest16 +# 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) +rtest16: + $(DRIVER) -t trace16.txt -s $(TSHREF) -a $(TSHARGS) + +# clean up +clean: + rm -f $(FILES) *.o *~ + + diff --git a/03_shlab/README b/03_shlab/README new file mode 100644 index 0000000..f30066f --- /dev/null +++ b/03_shlab/README @@ -0,0 +1,22 @@ +************************************ +* CSE4009 Assignment 3 - 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 16 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/03_shlab/myint.c b/03_shlab/myint.c new file mode 100644 index 0000000..f13fd1a --- /dev/null +++ b/03_shlab/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/03_shlab/myspin.c b/03_shlab/myspin.c new file mode 100644 index 0000000..013c166 --- /dev/null +++ b/03_shlab/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/03_shlab/mysplit.c b/03_shlab/mysplit.c new file mode 100644 index 0000000..0e95865 --- /dev/null +++ b/03_shlab/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/03_shlab/mystop.c b/03_shlab/mystop.c new file mode 100644 index 0000000..9e9be1a --- /dev/null +++ b/03_shlab/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/03_shlab/sdriver.pl b/03_shlab/sdriver.pl new file mode 100755 index 0000000..852bf3d --- /dev/null +++ b/03_shlab/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/03_shlab/trace01.txt b/03_shlab/trace01.txt new file mode 100644 index 0000000..9c8561e --- /dev/null +++ b/03_shlab/trace01.txt @@ -0,0 +1,5 @@ +# +# trace01.txt - Properly terminate on EOF. +# +CLOSE +WAIT diff --git a/03_shlab/trace02.txt b/03_shlab/trace02.txt new file mode 100644 index 0000000..e97643b --- /dev/null +++ b/03_shlab/trace02.txt @@ -0,0 +1,5 @@ +# +# trace02.txt - Process builtin quit command. +# +quit +WAIT diff --git a/03_shlab/trace03.txt b/03_shlab/trace03.txt new file mode 100644 index 0000000..be8869c --- /dev/null +++ b/03_shlab/trace03.txt @@ -0,0 +1,5 @@ +# +# trace03.txt - Run a foreground job. +# +/bin/echo tsh> quit +quit diff --git a/03_shlab/trace04.txt b/03_shlab/trace04.txt new file mode 100644 index 0000000..554df0e --- /dev/null +++ b/03_shlab/trace04.txt @@ -0,0 +1,5 @@ +# +# trace04.txt - Run a background job. +# +/bin/echo -e tsh> ./myspin 1 \046 +./myspin 1 & diff --git a/03_shlab/trace05.txt b/03_shlab/trace05.txt new file mode 100644 index 0000000..03c1876 --- /dev/null +++ b/03_shlab/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/03_shlab/trace06.txt b/03_shlab/trace06.txt new file mode 100644 index 0000000..bfa3890 --- /dev/null +++ b/03_shlab/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/03_shlab/trace07.txt b/03_shlab/trace07.txt new file mode 100644 index 0000000..259a285 --- /dev/null +++ b/03_shlab/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/03_shlab/trace08.txt b/03_shlab/trace08.txt new file mode 100644 index 0000000..49be19f --- /dev/null +++ b/03_shlab/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/03_shlab/trace09.txt b/03_shlab/trace09.txt new file mode 100644 index 0000000..340d998 --- /dev/null +++ b/03_shlab/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/03_shlab/trace10.txt b/03_shlab/trace10.txt new file mode 100644 index 0000000..e7de996 --- /dev/null +++ b/03_shlab/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/03_shlab/trace11.txt b/03_shlab/trace11.txt new file mode 100644 index 0000000..d2f8663 --- /dev/null +++ b/03_shlab/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/03_shlab/trace12.txt b/03_shlab/trace12.txt new file mode 100644 index 0000000..88455e3 --- /dev/null +++ b/03_shlab/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/03_shlab/trace13.txt b/03_shlab/trace13.txt new file mode 100644 index 0000000..d734cbc --- /dev/null +++ b/03_shlab/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/03_shlab/trace14.txt b/03_shlab/trace14.txt new file mode 100644 index 0000000..8086580 --- /dev/null +++ b/03_shlab/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/03_shlab/trace15.txt b/03_shlab/trace15.txt new file mode 100644 index 0000000..2cc780e --- /dev/null +++ b/03_shlab/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/03_shlab/trace16.txt b/03_shlab/trace16.txt new file mode 100644 index 0000000..822ba14 --- /dev/null +++ b/03_shlab/trace16.txt @@ -0,0 +1,16 @@ +# +# trace16.txt - Tests whether the shell can handle SIGTSTP and SIGINT +# signals that come from other processes instead of the terminal. +# + +/bin/echo tsh> ./mystop 2 +./mystop 2 + +SLEEP 3 + +/bin/echo tsh> jobs +jobs + +/bin/echo tsh> ./myint 2 +./myint 2 + diff --git a/03_shlab/tsh.c b/03_shlab/tsh.c new file mode 100644 index 0000000..82443dc --- /dev/null +++ b/03_shlab/tsh.c @@ -0,0 +1,516 @@ +/* + * tsh - A tiny shell program with job control + * + * Name: + * Student id: + */ +#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 */ + +/*---------------------------------------------------------------------------- + * 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 sigint_handler(int sig); +void sigtstp_handler(int sig); + +/*----------------------------------------------------------------------------*/ + +/* These functions are already implemented for your convenience */ +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/03_shlab/tshref b/03_shlab/tshref new file mode 100755 index 0000000000000000000000000000000000000000..d7e2108a6f19ac1c895128c46a63cf34cfdd53ab GIT binary patch literal 19278 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 BSvCLw literal 0 HcmV?d00001 diff --git a/03_shlab/tshref.out b/03_shlab/tshref.out new file mode 100644 index 0000000..83536bb --- /dev/null +++ b/03_shlab/tshref.out @@ -0,0 +1,218 @@ +./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