This commit is contained in:
s492459 2025-01-04 14:30:25 +01:00
commit c121092863
5 changed files with 232 additions and 0 deletions

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

39
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,39 @@
{
"configurations": [
{
"name": "C/C++: gcc build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
},
// { "description":"In this mode GDB will be attached to both processes after a call to fork() or vfork().",
// "text": "-gdb-set detach-on-fork off",
// "ignoreFailures": true
// },
// { "description": "The new process is debugged after a fork. The parent process runs unimpeded.",
// "text": "-gdb-set follow-fork-mode child",
// "ignoreFailures": true
// }
],
"preLaunchTask": "build main_logging.c",
"miDebuggerPath": "/usr/bin/gdb"
}
],
"version": "2.0.0"
}

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"files.associations": {
"unistd.h": "c",
"wait.h": "c"
}
}

37
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,37 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build main.c",
"type": "shell",
"command": "/usr/bin/gcc",
"args": [
"-g",
"main.c",
"-o",
"a.out"
],
"group": "build",
"problemMatcher": [
"$gcc"
],
"detail": "Build the main.c file using gcc"
},
{
"label": "build main_logging.c",
"type": "shell",
"command": "/usr/bin/gcc",
"args": [
"-g",
"main_logging.c",
"-o",
"a.out"
],
"group": "build",
"problemMatcher": [
"$gcc"
],
"detail": "Build the main_logging.c file using gcc"
}
]
}

134
main.c Normal file
View File

@ -0,0 +1,134 @@
#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;
}