From 79e61d7dbf5bf5e28fdae5e8a2aa40d9e80b96cb Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 11 Aug 2026 11:14:13 +0000 Subject: cc --- .gitignore | 2 +- Makefile | 103 +++++++++++++ tsh.c | 509 ------------------------------------------------------------- tsh.cc | 509 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 613 insertions(+), 510 deletions(-) create mode 100644 Makefile delete mode 100644 tsh.c create mode 100644 tsh.cc diff --git a/.gitignore b/.gitignore index 0ba1c63..f152158 100644 --- a/.gitignore +++ b/.gitignore @@ -48,7 +48,7 @@ build-*/ CMakeFiles/ CMakeCache.txt cmake_install.cmake -Makefile +#Makefile install_manifest.txt compile_commands.json diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7e3c0ea --- /dev/null +++ b/Makefile @@ -0,0 +1,103 @@ +# Makefile for the CS:APP Shell Lab + +TEAM = NOBODY +VERSION = 1 +HANDINDIR = /afs/cs/academic/class/15213-f02/L5/handin +DRIVER = ./sdriver.pl +TSH = ./tsh +TSHREF = ./tshref +TSHARGS = "-p" +CXX = g++ +CXXFLAGS = -std=c++17 -Wall -Wno-write-strings -O2 +CC = gcc +CFLAGS = -Wall -O2 +FILES = $(TSH) ./myspin ./mysplit ./mystop ./myint + +all: $(FILES) + +$(TSH): tsh.cc + $(CXX) $(CXXFLAGS) -o $@ $< + +################## +# Handin your work +################## +handin: + cp tsh.cc $(HANDINDIR)/$(TEAM)-$(VERSION)-tsh.cc + + +################## +# 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) +test16: + $(DRIVER) -t trace16.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) +rtest16: + $(DRIVER) -t trace16.txt -s $(TSHREF) -a $(TSHARGS) + + +# clean up +clean: + rm -f $(FILES) *.o *~ diff --git a/tsh.c b/tsh.c deleted file mode 100644 index 7c2ea8d..0000000 --- a/tsh.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * tsh - A tiny shell program with job control - * - * - */ -#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/tsh.cc b/tsh.cc new file mode 100644 index 0000000..7c2ea8d --- /dev/null +++ b/tsh.cc @@ -0,0 +1,509 @@ +/* + * tsh - A tiny shell program with job control + * + * + */ +#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); +} + + + -- cgit v1.3.1-4-g156e