#include #include #include #include #include #include #include #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; }