|
|
@ -15,18 +15,6 @@ |
|
|
|
char *history[CMDLINE_HISTORY_MAX_QUANTITY]; |
|
|
|
int cmdline_amount = 0; |
|
|
|
|
|
|
|
/* if true, print additional output */ |
|
|
|
int verbose = 0; |
|
|
|
|
|
|
|
/* next job ID to allocate */ |
|
|
|
int nextjid = 1; |
|
|
|
|
|
|
|
/* environment variable */ |
|
|
|
extern char **environ; |
|
|
|
|
|
|
|
/* The job list */ |
|
|
|
struct job_t jobs[JOBS_MAX_QUANTITY]; |
|
|
|
|
|
|
|
int main() |
|
|
|
{ |
|
|
|
char *cmdline = NULL, *pwd = NULL; |
|
|
@ -38,15 +26,6 @@ int main() |
|
|
|
history[i] = (char *)calloc(CMDLINE_MAX_SIZE, sizeof(char)); |
|
|
|
} |
|
|
|
|
|
|
|
/* Install the signal handlers */ |
|
|
|
Signal(SIGINT, sigint_handler); /* ctrl-c */ |
|
|
|
Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */ |
|
|
|
Signal(SIGCHLD, sigchld_handler); /* Terminated or stopped child */ |
|
|
|
Signal(SIGQUIT, sigquit_handler); |
|
|
|
|
|
|
|
/* initiate job list */ |
|
|
|
initjobs(jobs); |
|
|
|
|
|
|
|
/* execute the shell's read, parse and execution loop */ |
|
|
|
do |
|
|
|
{ |
|
|
@ -203,10 +182,6 @@ int execute(char *cmdline, char **args) |
|
|
|
redirect_filename = (char *)calloc(REDIRECT_FILENAME_MAX_SIZE, sizeof(char)); |
|
|
|
memset(redirect_args, NULL, sizeof(redirect_args)); |
|
|
|
|
|
|
|
sigset_t mask_all, mask_prev; |
|
|
|
sigprocmask(SIG_BLOCK, NULL, &mask_all); |
|
|
|
sigaddset(&mask_all, SIGCHLD); |
|
|
|
|
|
|
|
bg = parseline(cmdline, args); |
|
|
|
redirect_flag = check_redirect(args, redirect_filename, redirect_args); |
|
|
|
pipe_num = check_pipe(args, pipe_arg_1, pipe_arg_2); |
|
|
@ -215,13 +190,10 @@ int execute(char *cmdline, char **args) |
|
|
|
{ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (pipe_num == 0) |
|
|
|
if (pipe_num == 0) /* no pipe */ |
|
|
|
{ |
|
|
|
if (!built_in(args)) /* built-in cmd? */ |
|
|
|
{ |
|
|
|
/* Prevent child processes from ending between parent processes, that is, between addJob and deleteJob. */ |
|
|
|
sigprocmask(SIG_BLOCK, &mask_all, &mask_prev); /* Shield SIGCHLD */ |
|
|
|
|
|
|
|
if ((pid = fork()) == 0) /* Child process */ |
|
|
|
{ |
|
|
|
if (redirect_flag == 1) /* redirect? */ |
|
|
@ -237,14 +209,6 @@ int execute(char *cmdline, char **args) |
|
|
|
dup(fd); |
|
|
|
} |
|
|
|
|
|
|
|
/* The child process inherits the parent's signal mask and will inherit it after exec,
|
|
|
|
so it needs to restore the signal mask before executing. */ |
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); /* Child process, unblock SIGCHLD */ |
|
|
|
|
|
|
|
/* Set the pid of the current process to the group number of the process group it belongs to. */ |
|
|
|
/* avoid being grouped with tsh */ |
|
|
|
setpgid(0, 0); |
|
|
|
|
|
|
|
if ((redirect_flag == 1) || (redirect_flag == 2)) |
|
|
|
{ |
|
|
|
|
|
|
@ -264,27 +228,17 @@ int execute(char *cmdline, char **args) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else /* parent process */ |
|
|
|
{ |
|
|
|
if (bg) /* bg task */ |
|
|
|
if (bg) |
|
|
|
{ |
|
|
|
addjob(jobs, pid, BG, cmdline); |
|
|
|
signal(SIGCHLD, SIG_IGN); |
|
|
|
} |
|
|
|
else /* fg task */ |
|
|
|
{ |
|
|
|
addjob(jobs, pid, FG, cmdline); |
|
|
|
} |
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
|
|
|
|
if (bg) /* Don't wait for background tasks to finish */ |
|
|
|
{ |
|
|
|
printf("[%d](%d)%s", pid2jid(pid), pid, cmdline); |
|
|
|
} |
|
|
|
else /* Wait for foreground tasks to finish */ |
|
|
|
else |
|
|
|
{ |
|
|
|
waitfg(pid); |
|
|
|
waitpid(pid, NULL, 0); |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -292,7 +246,10 @@ int execute(char *cmdline, char **args) |
|
|
|
{ |
|
|
|
int fds[2]; |
|
|
|
pid_t prog_1, prog_2; |
|
|
|
sigprocmask(SIG_BLOCK, &mask_all, &mask_prev); |
|
|
|
|
|
|
|
printf("%s %s %s %s %s %s\n", pipe_arg_1[0], pipe_arg_1[1], pipe_arg_1[3], pipe_arg_1[4], pipe_arg_1[5]); |
|
|
|
|
|
|
|
printf("%s %s %s %s %s %s\n", pipe_arg_2[0], pipe_arg_2[1], pipe_arg_2[3], pipe_arg_2[4], pipe_arg_2[5]); |
|
|
|
|
|
|
|
if ((prog_1 = fork()) == 0) /* Child process 1 */ |
|
|
|
{ |
|
|
@ -300,16 +257,12 @@ int execute(char *cmdline, char **args) |
|
|
|
dup2(fds[1], 2); |
|
|
|
close(fds[0]); |
|
|
|
close(fds[1]); |
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
setpgid(0, 0); |
|
|
|
|
|
|
|
if (execvp(pipe_arg_1[0], pipe_arg_1) <= 0) |
|
|
|
{ |
|
|
|
printf("%s: Command not found\n", pipe_arg_1[0]); |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
_exit(127); |
|
|
|
} |
|
|
|
|
|
|
|
if ((prog_2 = fork()) == 0) /* Child process 1 */ |
|
|
@ -317,23 +270,21 @@ int execute(char *cmdline, char **args) |
|
|
|
dup2(fds[0], 0); |
|
|
|
close(fds[0]); |
|
|
|
close(fds[1]); |
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
setpgid(0, 0); |
|
|
|
|
|
|
|
if (execvp(pipe_arg_2[0], pipe_arg_2) <= 0) |
|
|
|
{ |
|
|
|
printf("%s: Command not found\n", pipe_arg_2[0]); |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
_exit(127); |
|
|
|
} |
|
|
|
|
|
|
|
close(fds[0]); |
|
|
|
close(fds[1]); |
|
|
|
|
|
|
|
waitfg(prog_1); |
|
|
|
waitfg(prog_2); |
|
|
|
wait(0); |
|
|
|
wait(0); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
@ -354,11 +305,16 @@ int built_in(char **args) |
|
|
|
} |
|
|
|
else if (!strcmp(args[0], "mytop")) |
|
|
|
{ |
|
|
|
return builtin_mytop(args); |
|
|
|
} |
|
|
|
else if (!strcmp(args[0], "jobs")) |
|
|
|
{ |
|
|
|
return builtin_jobs(args); |
|
|
|
int flag = builtin_mytop(); |
|
|
|
if (flag == -1) |
|
|
|
{ |
|
|
|
printf("yeeshell: unable to get memory info.\n"); |
|
|
|
} |
|
|
|
else if (flag == -2) |
|
|
|
{ |
|
|
|
printf("yeeshell: unable to get CPU info.\n"); |
|
|
|
} |
|
|
|
return flag; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
@ -401,343 +357,44 @@ int builtin_history(char **args) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
int builtin_jobs(char **args) |
|
|
|
{ |
|
|
|
/* To prevent interruptions, block all signals. */ |
|
|
|
sigset_t mask_all, mask_prev; |
|
|
|
sigfillset(&mask_all); |
|
|
|
sigprocmask(SIG_SETMASK, &mask_all, &mask_prev); |
|
|
|
|
|
|
|
for (int i = 0; i < JOBS_MAX_QUANTITY; 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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); /* unclock */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
int builtin_mytop(char **args) |
|
|
|
int builtin_mytop() |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
int do_bgfg(char **args) |
|
|
|
{ |
|
|
|
/* initialize variables */ |
|
|
|
struct job_t *currentJob; |
|
|
|
int jid; |
|
|
|
pid_t pid; |
|
|
|
sigset_t mask_all, mask_prev; |
|
|
|
sigfillset(&mask_all); |
|
|
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask_all, &mask_prev); |
|
|
|
|
|
|
|
/* bg or fg has the argument? */ |
|
|
|
if (args[1] == NULL) |
|
|
|
int memory_flag = 0, CPU_flag = 0; |
|
|
|
memory_flag = mytop_memory(); |
|
|
|
CPU_flag = mytop_CPU(); |
|
|
|
if (!memory_flag) |
|
|
|
{ |
|
|
|
printf("%s command requires PID or %%jobid argument\n", args[0]); |
|
|
|
return 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
/* if process by jid, gets the corresponding Job structure*/ |
|
|
|
else if (args[1][0] == '%') |
|
|
|
else if (!CPU_flag) |
|
|
|
{ |
|
|
|
jid = atoi(args[1][1]); |
|
|
|
currentJob = getjobjid(jobs, jid); |
|
|
|
if (currentJob == NULL) |
|
|
|
{ |
|
|
|
printf("%%%d: No such job\n", jid); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
pid = currentJob->pid; |
|
|
|
return -2; |
|
|
|
} |
|
|
|
/* if process by pid, gets the corresponding Job structure */ |
|
|
|
else |
|
|
|
{ |
|
|
|
pid = atoi(args[1]); |
|
|
|
currentJob = getjobpid(jobs, pid); |
|
|
|
if (pid <= 0) |
|
|
|
{ |
|
|
|
printf("%s: argument must be a PID or %%jobid\n", args[0]); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
currentJob = getjobpid(jobs, pid); |
|
|
|
if (currentJob == NULL) |
|
|
|
{ |
|
|
|
printf("(%d): No such process\n", pid); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* bg or fg? */ |
|
|
|
if (!strcmp(args[0], "bg")) /* if bg */ |
|
|
|
{ |
|
|
|
currentJob->state = BG; |
|
|
|
printf("[%d] (%d) %s", currentJob->jid, pid, currentJob->cmdline); |
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
kill(-pid, SIGCONT); /* send the SIGCONT to the pid */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
else if (!strcmp(args[0], "fg")) /* if fg */ |
|
|
|
{ |
|
|
|
currentJob->state = FG; |
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
kill(-pid, SIGCONT); /* send the SIGCONT to the pid */ |
|
|
|
waitfg(currentJob->pid); /* Child process switched to FG, so wait for it to finish */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
else if (!strcmp(args[0], "kill")) |
|
|
|
{ |
|
|
|
sigprocmask(SIG_SETMASK, &mask_prev, NULL); |
|
|
|
kill(-pid, SIGQUIT); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
void waitfg(pid_t pid) |
|
|
|
{ |
|
|
|
sigset_t m; |
|
|
|
sigemptyset(&m); |
|
|
|
while (pid == fgpid(jobs)) |
|
|
|
{ |
|
|
|
/* Wake up when there is a signal to check whether the foreground process PID change, */ |
|
|
|
/* change means that the foreground process is over. */ |
|
|
|
sigsuspend(&m); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
void initjobs(struct job_t *jobs) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
clearjob(&jobs[i]); |
|
|
|
} |
|
|
|
|
|
|
|
int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
if (pid < 1) |
|
|
|
return 0; |
|
|
|
|
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
{ |
|
|
|
if (jobs[i].pid == 0) |
|
|
|
{ |
|
|
|
jobs[i].pid = pid; |
|
|
|
jobs[i].state = state; |
|
|
|
jobs[i].jid = nextjid++; |
|
|
|
if (nextjid > JOBS_MAX_QUANTITY) |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
void listjobs(struct job_t *jobs) |
|
|
|
{ |
|
|
|
for (int i = 0; i < JOBS_MAX_QUANTITY; 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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int deletejob(struct job_t *jobs, pid_t pid) |
|
|
|
int mytop_memory() |
|
|
|
{ |
|
|
|
int i; |
|
|
|
FILE *fp = NULL; |
|
|
|
int pagesize; |
|
|
|
long total = 0, free = 0, cached = 0; |
|
|
|
|
|
|
|
if (pid < 1) |
|
|
|
return 0; |
|
|
|
|
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
if ((fp = fopen("/proc/meminfo", "r")) == NULL) |
|
|
|
{ |
|
|
|
if (jobs[i].pid == pid) |
|
|
|
{ |
|
|
|
clearjob(&jobs[i]); |
|
|
|
nextjid = maxjid(jobs) + 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void clearjob(struct job_t *job) |
|
|
|
{ |
|
|
|
job->pid = 0; |
|
|
|
job->jid = 0; |
|
|
|
job->state = UNDF; |
|
|
|
job->cmdline[0] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
int pid2jid(pid_t pid) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
if (pid < 1) |
|
|
|
return 0; |
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
if (jobs[i].pid == pid) |
|
|
|
{ |
|
|
|
return jobs[i].jid; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
pid_t fgpid(struct job_t *jobs) |
|
|
|
{ |
|
|
|
for (int i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
if (jobs[i].state == FG) |
|
|
|
return jobs[i].pid; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
struct job_t *getjobpid(struct job_t *jobs, pid_t pid) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
if (pid < 1) |
|
|
|
return NULL; |
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
if (jobs[i].pid == pid) |
|
|
|
return &jobs[i]; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
struct job_t *getjobjid(struct job_t *jobs, int jid) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
if (jid < 1) |
|
|
|
return NULL; |
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
if (jobs[i].jid == jid) |
|
|
|
return &jobs[i]; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
int maxjid(struct job_t *jobs) |
|
|
|
{ |
|
|
|
int i, max = 0; |
|
|
|
|
|
|
|
for (i = 0; i < JOBS_MAX_QUANTITY; i++) |
|
|
|
{ |
|
|
|
if (jobs[i].jid > max) |
|
|
|
{ |
|
|
|
max = jobs[i].jid; |
|
|
|
} |
|
|
|
} |
|
|
|
return max; |
|
|
|
} |
|
|
|
|
|
|
|
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) |
|
|
|
fprintf(stdout, "%s: %s\n", 'Signal Error', strerror(errno)); |
|
|
|
return (old_action.sa_handler); |
|
|
|
} |
|
|
|
|
|
|
|
void sigchld_handler(int signal) |
|
|
|
{ |
|
|
|
pid_t pid; |
|
|
|
int status; |
|
|
|
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) |
|
|
|
{ |
|
|
|
if (WIFEXITED(status)) /* Normal termination */ |
|
|
|
{ |
|
|
|
deletejob(jobs, pid); |
|
|
|
} |
|
|
|
if (WIFSTOPPED(status)) /* Task suspension */ |
|
|
|
{ |
|
|
|
struct job_t *job = getjobpid(jobs, pid); |
|
|
|
int jid = pid2jid(pid); |
|
|
|
printf("Job [%d] (%d) stopped by signal %d\n", jid, pid, WSTOPSIG(status)); |
|
|
|
job->state = ST; |
|
|
|
} |
|
|
|
if (WIFSIGNALED(status)) /* Task terminated */ |
|
|
|
{ |
|
|
|
int jid = pid2jid(pid); |
|
|
|
printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status)); |
|
|
|
deletejob(jobs, pid); |
|
|
|
} |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
fscanf(fp, "%u %lu %lu %lu", &pagesize, &total, &free, &cached); |
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
void sigint_handler(int signal) |
|
|
|
{ |
|
|
|
pid_t pid = fgpid(jobs); |
|
|
|
if (pid != 0) |
|
|
|
{ |
|
|
|
kill(-pid, signal); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
printf("memmory(KBytes):\t%ld total\t%ld free\t%ld cached\n", (pagesize * total) / 1024, (pagesize * free) / 1024, (pagesize * cached) / 1024); |
|
|
|
|
|
|
|
void sigtstp_handler(int signal) |
|
|
|
{ |
|
|
|
pid_t pid = fgpid(jobs); |
|
|
|
if (pid > 0) |
|
|
|
{ |
|
|
|
kill(-pid, signal); |
|
|
|
} |
|
|
|
return; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
void sigquit_handler(int signal) |
|
|
|
int mytop_CPU() |
|
|
|
{ |
|
|
|
printf("Terminating after receipt of SIGQUIT signal\n"); |
|
|
|
exit(1); |
|
|
|
} |