148 lines
3.4 KiB
C
148 lines
3.4 KiB
C
#include<stdio.h>
|
|
#include<stdlib.h>
|
|
#include<sys/wait.h>
|
|
#include<unistd.h>
|
|
#include<string.h>
|
|
#include<readline/readline.h>
|
|
#include<readline/history.h>
|
|
#include<signal.h>
|
|
#include"include/redirection.h"
|
|
pid_t backgroundPids[64];
|
|
int backgroundCount = 0;
|
|
void handleSIGINT(int sig) {
|
|
printf("\n");
|
|
}
|
|
void handleSIGCHLD(int sig) {
|
|
int pid = waitpid(-1, NULL, WNOHANG);
|
|
for(int i = 0; i < backgroundCount; i++) {
|
|
if(backgroundPids[i] == pid) {
|
|
printf("\n[done] %d\n", pid);
|
|
backgroundPids[i] = 0; // clear it
|
|
}
|
|
}
|
|
}
|
|
int detectBackground(char **args) {
|
|
for (int i = 0; args[i] != NULL; i++) {
|
|
if (strcmp(args[i], "&") == 0) {
|
|
args[i] = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
int seperatePipe(char **args) {
|
|
for(int i = 0; args[i] != NULL; i++) {
|
|
if (strcmp(args[i], "|") == 0) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
void executePipe(char **args, int pipeIndex) {
|
|
args[pipeIndex] = NULL;
|
|
char **cmd1 = args;
|
|
char **cmd2 = args + pipeIndex + 1;
|
|
int fd[2];
|
|
pipe(fd);
|
|
pid_t pid1 = fork();
|
|
if (pid1 == 0) {
|
|
dup2(fd[1], STDOUT_FILENO);
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
signal(SIGINT, SIG_DFL);
|
|
execvp(cmd1[0], cmd1);
|
|
perror("tinysh");
|
|
exit(1);
|
|
}
|
|
pid_t pid2 = fork();
|
|
if (pid2 == 0) {
|
|
dup2(fd[0], STDIN_FILENO);
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
signal(SIGINT, SIG_DFL);
|
|
execvp(cmd2[0], cmd2);
|
|
perror("tinysh");
|
|
exit(1);
|
|
}
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
if (pid1 > 0) wait(NULL);
|
|
if(pid2 > 0) wait(NULL);
|
|
}
|
|
int handleBuiltins(char **args) {
|
|
if(strcmp(args[0], "cd") == 0) {
|
|
chdir(args[1] == NULL ? getenv("HOME") : args[1]);
|
|
return 1;
|
|
}
|
|
else if(strcmp(args[0], "exit") == 0) {
|
|
exit(0);
|
|
} else { return 0;}
|
|
}
|
|
char **parse(char *line) {
|
|
char **args= malloc(64 * sizeof(char *));
|
|
int i = 0;
|
|
char *token = strtok(line, " \t\n");
|
|
while(token !=NULL) {
|
|
args[i] = token;
|
|
i++;
|
|
token = strtok(NULL, " \t\n");
|
|
}
|
|
args[i] = NULL;
|
|
return args;
|
|
}
|
|
int main() {
|
|
signal(SIGINT, handleSIGINT);
|
|
signal(SIGCHLD, handleSIGCHLD);
|
|
while(1) {
|
|
char *user = getenv("USER");
|
|
char dir[1024];
|
|
getcwd(dir, sizeof(dir));
|
|
char host[1024];
|
|
gethostname(host, sizeof(host));
|
|
char prompt[2051];
|
|
char *home = getenv("HOME");
|
|
if(strncmp(dir, home, strlen(home)) == 0) {
|
|
snprintf(prompt, sizeof(prompt), "%s@%s ~%s$ ", user, host, dir + strlen(home));
|
|
} else {
|
|
snprintf(prompt, sizeof(prompt), "%s@%s %s$ ", user, host, dir);
|
|
}
|
|
char *line = readline(prompt);
|
|
if(line == NULL) return 0;
|
|
if(line && *line) add_history(line);
|
|
char **parsed = parse(line);
|
|
if(parsed[0] == NULL) { free(parsed); free(line); continue; }
|
|
if(handleBuiltins(parsed)) { free(line); free(parsed); continue; }
|
|
int background = detectBackground(parsed);
|
|
int pipeIndex = seperatePipe(parsed);
|
|
if (pipeIndex != -1) {
|
|
executePipe(parsed, pipeIndex);
|
|
free(line);
|
|
free(parsed);
|
|
continue;
|
|
}
|
|
char *filename;
|
|
int redirectionType = detectRedirect(parsed, &filename);
|
|
if (redirectionType) {
|
|
executeRedirect(parsed, redirectionType, filename);
|
|
free(parsed);
|
|
free(line);
|
|
continue;
|
|
}
|
|
pid_t pid = fork();
|
|
if(pid == 0) {
|
|
signal(SIGINT, SIG_DFL);
|
|
if(execvp(parsed[0], parsed) == -1 ) {
|
|
perror("tinysh");
|
|
exit(1);
|
|
}
|
|
} else if(pid > 0) {
|
|
if(background) {
|
|
printf("{background} %d \n", pid);
|
|
backgroundPids[backgroundCount++] = pid;
|
|
}
|
|
else wait(NULL);
|
|
}
|
|
free(parsed);
|
|
free(line);
|
|
}
|
|
}
|
|
|