diff --git a/tsh.c b/tsh.c index 69e78ba..7c44122 100644 --- a/tsh.c +++ b/tsh.c @@ -1,14 +1,14 @@ -/* +/* * tsh - A tiny shell program with job control * * You __MUST__ add your user information here below * hallo2 * === User information === * Group: Team Dolan - * User 1: haukurr11 - * SSN: 1911912269 + * User 1: haukurr11 + * SSN: 1911912269 * User 2: knutur11 - * SSN: 1701834449 + * SSN: 1701834449 * === End User Information === */ #include @@ -33,7 +33,7 @@ #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 @@ -72,27 +72,27 @@ void sigchld_handler(int sig); void sigtstp_handler(int sig); void sigint_handler(int sig); - /*Wrapper functions that we made */ - pid_t Fork(void); - pid_t Setgpid(pid_t pid, pid_t pgid); - int Kill(pid_t pid, int signal); - int Sigaddset(sigset_t *set, int signal); - int Sigemptyset(sigset_t *set); - int Sigprocmask(int sig, const sigset_t *set, sigset_t *set_last); +/*Wrapper functions that we made */ +pid_t Fork(void); +pid_t Setgpid(pid_t pid, pid_t pgid); +int Kill(pid_t pid, int signal); +int Sigaddset(sigset_t *set, int signal); +int Sigemptyset(sigset_t *set); +int Sigprocmask(int sig, const sigset_t *set, sigset_t *set_last); /* Here are helper routines that we've provided for you */ -int parseline(const char *cmdline, char **argv); +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 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); +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); +struct job_t *getjobjid(struct job_t *jobs, int jid); +int pid2jid(pid_t pid); void listjobs(struct job_t *jobs); void usage(void); @@ -102,9 +102,9 @@ typedef void handler_t(int); handler_t *Signal(int signum, handler_t *handler); /* - * main - The shell's main routine + * main - The shell's main routine */ -int main(int argc, char **argv) +int main(int argc, char **argv) { char c; char cmdline[MAXLINE]; @@ -119,16 +119,16 @@ int main(int argc, char **argv) switch (c) { case 'h': /* print help message */ usage(); - break; + break; case 'v': /* emit additional diagnostic info */ verbose = 1; - break; + break; case 'p': /* don't print a prompt */ emit_prompt = 0; /* handy for automatic testing */ - break; - default: + break; + default: usage(); - } + } } /* Install the signal handlers */ @@ -139,7 +139,7 @@ int main(int argc, char **argv) Signal(SIGCHLD, sigchld_handler); /* Terminated or stopped child */ /* This one provides a clean way to kill the shell */ - Signal(SIGQUIT, sigquit_handler); + Signal(SIGQUIT, sigquit_handler); /* Initialize the job list */ initjobs(jobs); @@ -147,39 +147,39 @@ int main(int argc, char **argv) /* Execute the shell's read/eval loop */ while (1) { - /* Read command line */ - if (emit_prompt) { - printf("%s", prompt); + /* 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); - } - 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. + * when we type ctrl-c (ctrl-z) at the keyboard. */ void eval(char *cmdline) @@ -220,14 +220,14 @@ 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. + * the user has requested a FG job. */ -int parseline(const char *cmdline, char **argv) +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 */ @@ -238,48 +238,48 @@ int parseline(const char *cmdline, char **argv) strcpy(buf, cmdline); buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */ while (*buf && (*buf == ' ')) /* ignore leading spaces */ - buf++; + 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++; + 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; + return 1; /* should the job run in the background? */ if ((bg = (*argv[argc-1] == '&')) != 0) { - argv[--argc] = NULL; + argv[--argc] = NULL; } return bg; } -/* +/* * builtin_cmd - If the user has typed a built-in command then execute - * it immediately. + * it immediately. */ int builtin_cmd(char **argv) { @@ -293,13 +293,13 @@ int builtin_cmd(char **argv) return 1; } else if(!strcmp(argv[0],"jobs")) /* get the list over all jobs */ - { + { listjobs(jobs); return 1; - } + } return 0; /* Not a builtin command */ -} -/* +} +/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) @@ -307,19 +307,19 @@ void do_bgfg(char **argv) struct job_t *job = NULL; if(argv[1] != NULL) { - if( argv[1][0] == '%') - { - char *number = &argv[1][1]; - int jid = atoi(number); - job = getjobjid(jobs,jid); - if(job == NULL) - { - printf("%s: No such job\n",argv[1]); - return; - } - } - else if( isdigit(argv[1][0]) ) - { + if( argv[1][0] == '%') + { + char *number = &argv[1][1]; + int jid = atoi(number); + job = getjobjid(jobs,jid); + if(job == NULL) + { + printf("%s: No such job\n",argv[1]); + return; + } + } + else if( isdigit(argv[1][0]) ) + { pid_t pid = atoi(argv[1]); job = getjobpid(jobs,pid); if(job == NULL) @@ -327,12 +327,12 @@ void do_bgfg(char **argv) printf("(%d): No such process\n",pid); return; } - } - else - { - printf("%s: argument must be a PID or %%jobid\n",argv[0]); - return; - } + } + else + { + printf("%s: argument must be a PID or %%jobid\n",argv[0]); + return; + } } else { printf("%s command requires PID or %%jobid argument\n",argv[0] ); @@ -341,7 +341,7 @@ void do_bgfg(char **argv) int killpid = job->pid; Kill(-killpid,SIGCONT); - sigset_t mask; + sigset_t mask; sigemptyset(&mask); sigaddset(&mask,SIGCHLD); @@ -363,7 +363,7 @@ void do_bgfg(char **argv) } -/* +/* * waitfg - Block until process pid is no longer the foreground process */ void waitfg(pid_t pid) @@ -380,20 +380,20 @@ void waitfg(pid_t pid) * 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. + * currently running children to terminate. */ -void sigchld_handler(int sig) +void sigchld_handler(int sig) { pid_t pid; int status; int jid; int signal = -1; - struct job_t *job; + struct job_t *job; while( (pid = waitpid(-1,&status,WUNTRACED|WNOHANG))>0) { jid = pid2jid(pid); @@ -403,7 +403,7 @@ void sigchld_handler(int sig) { if(job != NULL) { - job->state=ST; + job->state=ST; printf("Job [%d] (%d) stopped by signal %d\n",jid,pid,20); } else @@ -424,19 +424,19 @@ void sigchld_handler(int sig) else if( WIFEXITED(status) ) /* child process has exited */ { deletejob(jobs,pid); - } - else - unix_error("waitpid error"); + } + else + unix_error("waitpid error"); } 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. + * to the foreground job. */ -void sigint_handler(int sig) +void sigint_handler(int sig) { int pid = fgpid(jobs); if(pid == 0) /* error */ @@ -448,9 +448,9 @@ void sigint_handler(int sig) /* * 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. + * foreground job by sending it a SIGTSTP. */ -void sigtstp_handler(int sig) +void sigtstp_handler(int sig) { int pid = fgpid(jobs); if(pid == 0) /* error */ @@ -480,60 +480,60 @@ void initjobs(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) - clearjob(&jobs[i]); + clearjob(&jobs[i]); } /* maxjid - Returns largest allocated job ID */ -int maxjid(struct job_t *jobs) +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; + 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 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); + 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; } - return 1; -} -} -printf("Tried to create too many jobs\n"); -return 0; + } + 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 deletejob(struct job_t *jobs, pid_t pid) { -int i; + int i; -if (pid < 1) -return 0; + 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; - } + for (i = 0; i < MAXJOBS; i++) { + if (jobs[i].pid == pid) { + clearjob(&jobs[i]); + nextjid = maxjid(jobs)+1; + return 1; + } } return 0; } @@ -543,8 +543,8 @@ pid_t fgpid(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) - if (jobs[i].state == FG) - return jobs[i].pid; + if (jobs[i].state == FG) + return jobs[i].pid; return 0; } @@ -553,63 +553,63 @@ struct job_t *getjobpid(struct job_t *jobs, pid_t pid) { int i; if (pid < 1) - return NULL; + return NULL; for (i = 0; i < MAXJOBS; i++) - if (jobs[i].pid == pid) - return &jobs[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) +struct job_t *getjobjid(struct job_t *jobs, int jid) { int i; if (jid < 1) - return NULL; + return NULL; for (i = 0; i < MAXJOBS; i++) - if (jobs[i].jid == jid) - return &jobs[i]; + if (jobs[i].jid == jid) + return &jobs[i]; return NULL; } /* pid2jid - Map process ID to job ID */ -int pid2jid(pid_t pid) +int pid2jid(pid_t pid) { int i; if (pid < 1) - return 0; + return 0; for (i = 0; i < MAXJOBS; i++) - if (jobs[i].pid == pid) { + if (jobs[i].pid == pid) { return jobs[i].jid; } return 0; } /* listjobs - Print the job list */ -void listjobs(struct job_t *jobs) +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); + 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); } - printf("%s", jobs[i].cmdline); - } } } /****************************** @@ -617,13 +617,13 @@ void listjobs(struct job_t *jobs) ******************************/ /****************************** - * Our helper wrappers + * Our helper wrappers ******************************/ pid_t Fork(void) { int pid =-1; - if((pid = fork()) < 0) + if((pid = fork()) < 0) { unix_error("Fork Error!"); exit(1); @@ -685,7 +685,7 @@ int Sigprocmask(int sig, const sigset_t *set, sigset_t *set_last) /* * usage - print a help message */ -void usage(void) +void usage(void) { printf("Usage: shell [-hvp]\n"); printf(" -h print this message\n"); @@ -715,16 +715,16 @@ void app_error(char *msg) /* * Signal - wrapper for the sigaction function */ -handler_t *Signal(int signum, handler_t *handler) +handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; - action.sa_handler = handler; + 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"); + unix_error("Signal error"); return (old_action.sa_handler); } @@ -732,7 +732,7 @@ handler_t *Signal(int signum, handler_t *handler) * sigquit_handler - The driver program can gracefully terminate the * child shell by sending it a SIGQUIT signal. */ -void sigquit_handler(int sig) +void sigquit_handler(int sig) { printf("Terminating after receipt of SIGQUIT signal\n"); exit(1); @@ -741,3 +741,4 @@ void sigquit_handler(int sig) +