diff --git a/result.txt b/result.txt index 561402c..5c5a139 100755 --- a/result.txt +++ b/result.txt @@ -1,10 +1,5 @@ -total 56 -drwxr-xr-x 4 root root 120 Mar 16 23:39 . -dr-xr-x---. 14 root root 4096 Mar 16 23:39 .. -drwxr-xr-x 8 root root 201 Mar 16 22:49 .git --rw-r--r-- 1 root root 46 Mar 10 17:40 README.md --rwx------ 1 root root 0 Mar 16 23:39 result.txt -drwxr-xr-x 2 root root 64 Mar 16 11:27 .vscode --rwxr-xr-x 1 root root 27936 Mar 16 23:39 yeeshell --rw-r--r-- 1 root root 15053 Mar 16 23:38 yeeshell.c --rw-r--r-- 1 root root 4043 Mar 16 23:36 yeeshell.h +README.md +result.txt +yeeshell +yeeshell.c +yeeshell.h diff --git a/yeeshell b/yeeshell index c8a9602..ca41902 100755 Binary files a/yeeshell and b/yeeshell differ diff --git a/yeeshell.c b/yeeshell.c index bed1ce3..1114bf2 100644 --- a/yeeshell.c +++ b/yeeshell.c @@ -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); } \ No newline at end of file diff --git a/yeeshell.h b/yeeshell.h index eb16d4a..a26c1f8 100644 --- a/yeeshell.h +++ b/yeeshell.h @@ -2,33 +2,19 @@ #define CMDLINE_MAX_SIZE 1024 /* max length of a single command line */ #define ARGS_MAX_QUANTITY 128 /* max args on a command line */ -#define BUFFER_MAX_SIZE 64 /* max size of a buffer which contains parsed arguments */ +#define BUFFER_MAX_SIZE 64 /* max size of a buffer which contains parsed arguments */ #define CMDLINE_DIV ' \t\r\n\a' #define CMDLINE_HISTORY_MAX_QUANTITY 256 #define JOBS_MAX_QUANTITY 16 #define PATH_MAX_SIZE 256 #define LS_BUF_SIZE 1024 #define REDIRECT_FILENAME_MAX_SIZE 64 /* redirection filename */ -#define REDIRECT_ARG_MAX_SIZE 16 /* redirection argument */ - -#define UNDF 0 /* undefined */ -#define FG 1 /* running in foreground */ -#define BG 2 /* running in background */ -#define ST 3 /* stopped */ +#define REDIRECT_ARG_MAX_SIZE 16 /* redirection argument */ #define REDIRECT_NO 0 /* no redirection */ #define REDIRECT_OUT 1 /* redirect output */ #define REDIRECT_IN 2 /* redirect input */ -/* job_t - The job struct */ -struct job_t -{ - pid_t pid; /* job PID */ - int jid; /* job ID [1, 2, ...] */ - int state; /* UNDEF, BG, FG, or ST */ - char cmdline[CMDLINE_MAX_SIZE]; /* command line */ -}; - /* readline - Get the command line */ char *readline(); @@ -48,75 +34,4 @@ int execute(char *cmdline, char **args); int built_in(char **args); int builtin_cd(char **args); int builtin_history(char **args); -int builtin_jobs(char **args); -int builtin_mytop(char **args); - -/* do_bgfg - Execute background/foregroung tasks */ -int do_bgfg(char **args); - -/* waitfg - Wait foreground jobs to finish */ -void waitfg(pid_t pid); - -/* initjobs - Initialize the job list */ -void initjobs(struct job_t *jobs); - -/* addjob - Add jobs to joblist */ -int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline); - -/* listjobs - Print the job list */ -void listjobs(struct job_t *jobs); - -/* deletejob - Delete a job whose PID=pid from the job list */ -int deletejob(struct job_t *jobs, pid_t pid); - -/* clearjob - Clear the entries in a job struct */ -void clearjob(struct job_t *job); - -/* pide2jid - Map process ID to job ID*/ -int pid2jid(pid_t pid); - -/* fgpid - Return PID of current foreground job, 0 if no such job */ -pid_t fgpid(struct job_t *jobs); - -/* getjobpid - Find a job (by PID) on the job list */ -struct job_t *getjobpid(struct job_t *jobs, pid_t pid); - -/* getjobjid - Find a job (by JID) on the job list */ -struct job_t *getjobjid(struct job_t *jobs, int jid); - -/* maxjid - Returns largest allocated job ID */ -int maxjid(struct job_t *jobs); - -/* Signal - wrapper for the sigaction function */ -typedef void handler_t(int); -handler_t *Signal(int signum, handler_t *handler); - -/* - * 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 signal); - -/* - * 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 signal); - -/* - * 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 signal); - -/* - * sigquit_handler - The driver program can gracefully terminate the - * child shell by sending it a SIGQUIT signal. - */ -void sigquit_handler(int signal); \ No newline at end of file +int builtin_mytop(); \ No newline at end of file