Last active
November 15, 2023 20:11
-
-
Save cod3smith/276d96922044e5374da20ac1c5006d3b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <sys/wait.h> | |
#include <string.h> | |
#include <errno.h> | |
#define BUFFER_SIZE 256 | |
#define MAX_COMMAND_LENGTH 100 | |
ssize_t custom_getline(char **lineptr, size_t n) { | |
if (*lineptr == NULL || n == 0) { | |
*lineptr = (char *)malloc(BUFFER_SIZE); | |
if (*lineptr == NULL) { | |
perror("malloc"); | |
return -1; | |
} | |
n = BUFFER_SIZE; | |
} | |
ssize_t bytesRead = read(STDIN_FILENO, *lineptr, n); | |
if (bytesRead == -1) { | |
perror("read"); | |
return -1; | |
} | |
return bytesRead; | |
} | |
void executeCommand(const char *command, char *const args[]) { | |
pid_t pid = fork(); | |
if (pid == -1) { | |
perror("fork"); | |
exit(EXIT_FAILURE); | |
} else if (pid == 0) { // Child process | |
execvp(command, args); | |
perror("execvp"); | |
exit(EXIT_FAILURE); | |
} else { // Parent process | |
int status; | |
waitpid(pid, &status, 0); | |
if (WIFEXITED(status)) { | |
printf("Exit Status: %d\n", WEXITSTATUS(status)); | |
} else { | |
printf("Error executing command '%s'.\n", command); | |
} | |
} | |
} | |
void handleCd(const char *directory) { | |
if (chdir(directory) != 0) { | |
perror("chdir"); | |
fprintf(stderr, "Error changing directory to '%s'.\n", directory); | |
} else { | |
printf("Changed directory to '%s'.\n", directory); | |
} | |
} | |
void handleSetenv(char *const args[]) { | |
if (args[1] != NULL && args[2] != NULL && args[3] == NULL) { | |
if (setenv(args[1], args[2], 1) != 0) { | |
perror("setenv"); | |
fprintf(stderr, "Error setting environment variable '%s'.\n", args[1]); | |
} else { | |
printf("Environment variable '%s' set to '%s'.\n", args[1], args[2]); | |
} | |
} else { | |
fprintf(stderr, "Usage: setenv <variable> <value>\n"); | |
} | |
} | |
void handleUnsetenv(char *const args[]) { | |
if (args[1] != NULL && args[2] == NULL) { | |
if (unsetenv(args[1]) != 0) { | |
perror("unsetenv"); | |
fprintf(stderr, "Error unsetting environment variable '%s'.\n", args[1]); | |
} else { | |
printf("Environment variable '%s' unset.\n", args[1]); | |
} | |
} else { | |
fprintf(stderr, "Usage: unsetenv <variable>\n"); | |
} | |
} | |
int tokenizeInput(char *line, char *args[]) { | |
int arg_count = 0; | |
char *token = strtok(line, " \t\n"); | |
while (token != NULL) { | |
args[arg_count++] = token; | |
token = strtok(NULL, " \t\n"); | |
} | |
args[arg_count] = NULL; | |
return arg_count; | |
} | |
void handleCommand(char *line) { | |
char *args[MAX_COMMAND_LENGTH]; | |
int arg_count; | |
while (1) { | |
printf("Enter a command: "); | |
fflush(stdout); | |
ssize_t bytesRead = custom_getline(&line, BUFFER_SIZE); | |
if (bytesRead == -1) { | |
fprintf(stderr, "Error reading input.\n"); | |
break; | |
} else if (bytesRead == 0) { | |
printf("End of file reached.\n"); | |
break; | |
} | |
arg_count = tokenizeInput(line, args); | |
if (arg_count > 0) { | |
if (strcmp(args[0], "exit") == 0) { | |
free(line); | |
exit(EXIT_SUCCESS); | |
} else if (strcmp(args[0], "cd") == 0) { | |
if (args[1] != NULL) { | |
handleCd(args[1]); | |
} else { | |
fprintf(stderr, "Usage: cd <directory>\n"); | |
} | |
} else if (strcmp(args[0], "mkdir") == 0) { | |
if (args[1] != NULL) { | |
char *mkdir_args[] = {"mkdir", args[1], NULL}; | |
executeCommand("/bin/mkdir", mkdir_args); | |
} else { | |
fprintf(stderr, "Usage: mkdir <directory>\n"); | |
} | |
} else if (strcmp(args[0], "setenv") == 0) { | |
handleSetenv(args); | |
} else if (strcmp(args[0], "unsetenv") == 0) { | |
handleUnsetenv(args); | |
} else if (strcmp(args[0], "ls") == 0) { | |
executeCommand("/bin/ls", args); | |
} else if (strcmp(args[0], "pwd") == 0) { | |
char cwd[1024]; | |
if (getcwd(cwd, sizeof(cwd)) != NULL) { | |
printf("Current working directory: %s\n", cwd); | |
} else { | |
perror("getcwd"); | |
} | |
} else if (strcmp(args[0], "env") == 0) { | |
executeCommand("/usr/bin/env", args); | |
} else { | |
executeCommand(args[0], args); | |
} | |
} | |
} | |
free(line); | |
} | |
int main() { | |
char *line = NULL; | |
handleCommand(line); | |
printf("Exiting CLI program.\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment