Make a swsh shell works under linux environment
-> which covers the files, signals, and IPC
A shell is a program that takes 1) input from a user, 2) interprets it, and 3) executes a command. swsh is a shell that implements only a small amount of functionality and can execute specific commands. It supports input / output redirection and pipeline functions.
The function of each symbol is the same as what we learned in the IPC class.
1) Determine the number of commands (when commands are connected by pipeline, etc.) (For each command)
2) Determine if input / output redirection was used
3) Analyzes the command type,
A. If you implement it yourself, create a child process (if necessary) to call that routine.
B. If you not implemented it yourself, create a child process to load and run the program.
4) If you create a child process, wait until it terminates
If swsh creates a new child process, make sure that it belongs to the new process group. (Make the pgid of that child process match its own pid)
If you create more than one process due to the use of pipes, make sure all processes belong to the group of processes you created first. (The pgido f the process must match the pid of the first child process created)
If swsh has created a child process, use the wait series system call to identify and remove the child process so that no zombie processes are created.
If a process receives a SIGTSTP signal generated by the Ctrl + Z key during execution, it will stop and halt the execution of the process as usual. At the same time, the parent process receives the SIGCHLD signal and returns true if the parent executes the WIFSTOPPED macro on the status value obtained by calling waitpid as follows: (option WUNTRACED of the waitpid system call)
If a child process is stopped (when WIFSTOPPED is true), it kills all associated processes by sending a SIGKILL signal to the process group to which the child belongs.
If an error occurs while executing the mv, rm, cd command(cmd_type3), the message specified in the table below is combined as follows according to the type of the error and output as standard error. (This problem can be solved by using <errno.h>)
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/types.h>
void handler(int sig)
{
exit(0);
}
int main()
{
char *cmd = NULL;
size_t size = 0;
char *arg[11];
while(1){
int i = 0;
getline(&cmd, &size, stdin);
cmd[strlen(cmd) - 1] = '\0';
if(strlen(cmd) == 0)
continue;
char *ptr = strtok(cmd, " ");
while(ptr != NULL){
arg[i++] = ptr;
ptr = strtok(NULL, " ");
}
arg[i] = NULL;
if(strcmp("quit", arg[0]) == 0) //"quit"
break;
char path[100];
sprintf(path, "/bin/%s", arg[0]);
for(int x = 0; x < i; x++){
if(strcmp(">", arg[x]) == 0){ //output redirection
int fd = open(arg[x+1], O_RDWR|O_CREAT|O_TRUNC, 0644);
if(fork() == 0){
dup2(fd, STDOUT_FILENO);
arg[x] = NULL;
execv(path, arg);
}
wait(NULL);
close(fd);
break;
}
else if(strcmp(">>", arg[x]) == 0){ //output redirection (appending)
int fd = open(arg[x+1], O_RDWR|O_APPEND, 0644);
if(fork() == 0){
dup2(fd, STDOUT_FILENO);
arg[x] = NULL;
execv(path, arg);
}
wait(NULL);
close(fd);
break;
}
else if(strcmp("<", arg[x]) == 0){ //input redirection
int fd = open(arg[x+1], O_RDONLY);
if(fork() == 0){
dup2(fd, STDIN_FILENO);
arg[x] = NULL;
execv(path, arg);
}
wait(NULL);
close(fd);
break;
}
else if(strcmp("|", arg[x]) == 0){ //pipeline
int fd[2];
pid_t pid1, pid2;
if(pipe(fd) < 0) exit(1);
if((pid1 = fork()) == 0){ //parent
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
arg[x] = NULL;
execv(path, arg);
}
wait(NULL);
if((pid2 = fork()) == 0){ //child
close(fd[1]);
char **arg2 = &arg[x + 1];
sprintf(path, "/bin/%s", arg2[0]);
dup2(fd[0], STDIN_FILENO);
execv(path, arg2);
}
close(fd[0]);
close(fd[1]);
wait(NULL);
break;
}
else if(strcmp("exit", arg[x]) == 0){ //exit
if(arg[x+1] != NULL){
int no = atoi(arg[x+1]);
printf("%d\n", no);
exit(no);
}
else{
printf("%d\n", 0);
exit(0);
}
}
else if(strcmp("cd", arg[x]) == 0){ //cd
if(chdir(arg[x+1]) != 0){
perror("cd");
}
break;
}
if(x == i - 1){ //ls, man, grep, sort, head, tail, cat, mv, rm, cp, pwd
if(fork() == 0){
execv(path, arg);
}
wait(NULL);
break;
}
} //for loop end
}
}