microshell_project/main.c
2025-01-04 14:30:25 +01:00

134 lines
3.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_SIZE 1024
// int LogCommandHistory(char* buf, char** command_log, int n) {
// command_log[n] = buf;
// }
void PrintCurrentDir() { // pwd
char cwd[MAX_SIZE];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("[%s] $ ", cwd);
} else {
perror("getcwd() error");
}
}
int ChangeDirectory(char** args) { // cd
args++; // Moving pointer to the next element (cd requires local or global path, the first argument is command name, so it's skipped)
char* path = args[0];
if (path == NULL || strcmp(path, "~") == 0) {
path = getenv("HOME");
}
if (chdir(path) != 0) {
perror("cd");
return -1;
}
return 0;
}
void PrintHelp() { // help
printf("C Microshell implementation by Maciej Życzyński\n");
}
int HandleBuiltInCommands(char* command, char** args) { // Manual implementation of commands unsupported by execvp()
if (strcmp(command, "cd") == 0) {
ChangeDirectory(args);
return 1;
}
else if (strcmp(command, "help") == 0) {
PrintHelp();
return 1;
}
else if (strcmp(command, "exit") == 0) {
return 2;
}
return 0;
}
int HandleCommand(char* command, char** args) { // Execute commands supported by execvp()
if (execvp(command, args) == -1) {
perror("Error executing command");
return -1;
}
return 0;
}
int ParseCommand(char* buf, char** command, char** args) {
char buf_cp[MAX_SIZE];
strcpy(buf_cp, buf); // Leave the original buffer (important for command history implementation)
buf_cp[strlen(buf_cp) - 1] = '\0'; // Remove newline from input string
char* token = strtok(buf_cp, " ");
int tok_count = 0;
if (token == NULL) { // Retrieve command and arguments
return -1;
}
*command = token;
while (token != NULL) {
args[tok_count] = token;
tok_count++;
token = strtok(NULL, " ");
}
args[tok_count] = NULL; // Manually add NULL at the end (execvp() requires the argument array to be null-terminated)
return 0;
}
int main() {
char buf[MAX_SIZE];
char* command_log[MAX_SIZE];
int n = 0;
while (1) {
PrintCurrentDir();
char* command;
char* args[MAX_SIZE];
fgets(buf, sizeof(buf), stdin);
if (ParseCommand(buf, &command, args) < 0) {
printf("Invalid command\n");
continue;
}
// LogCommandHistory(buf, &command_log, n);
// n++;
int handler_value = HandleBuiltInCommands(command, args);
if (handler_value == 2) { // Exit command
break;
}
else if (handler_value == 0) { // Not a built-in command
// Forking logic
pid_t pid = fork();
if (pid < 0) {
perror("Error while forking\n");
}
else if (pid == 0) { // Child process
if (HandleCommand(command, args) == -1) {
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
else { // Parent process
int status;
if (waitpid(pid, &status, 0) == -1) {
perror("Error with parent process\n");
}
}
}
}
return 0;
}