Skip to content

Instantly share code, notes, and snippets.

@cod3smith
Last active November 15, 2023 20:11
Show Gist options
  • Save cod3smith/276d96922044e5374da20ac1c5006d3b to your computer and use it in GitHub Desktop.
Save cod3smith/276d96922044e5374da20ac1c5006d3b to your computer and use it in GitHub Desktop.
#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