Files
tinysh/main.c
T
2026-05-12 17:32:57 +02:00

143 lines
3.3 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];
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);
}
}