FENIX_coreutils/sh.c
2020-12-13 14:15:04 -06:00

140 lines
3 KiB
C
Executable file

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <libgen.h>
#include <errno.h>
#include <limits.h>
#define ARG_SEP " " /* Argument separator for commands */
#define PROMPT " $ "
char** create_argv(char* command);
int get_argc(char* command);
char* prompt();
int cd(char* path);
int main() {
char** argv;
char* user_input;
pid_t child_pid;
int stat_loc; /* ??? (Needed for waitpid) */
signal(SIGINT, SIG_IGN);
while(1) {
user_input = prompt();
argv = create_argv(user_input);
if(strcmp(argv[0], "cd") == 0) {
if(cd(argv[1]) < 0) {
perror(argv[1]);
}
/* causes the fork to get skipped */
continue;
}
else if(strcmp(argv[0], "exit") == 0 ||
strcmp(argv[0], "quit") == 0) {
exit(0);
}
child_pid = fork();
if(child_pid < 0) {
/* Could not start child process. Check why and error out. */
if(errno == EAGAIN) {
perror("Could not execute command: insufficient resources");
exit(1);
}
else if(errno == ENOMEM) {
/* Is this out of RAM or out of storage? */
perror("Could not execute command: insufficient storage space");
exit(1);
}
else {
perror("Could not execute command: unknown failure");
exit(1);
}
}
else if(child_pid == 0) {
/* We are the child, so allow ^C */
signal(SIGINT, SIG_DFL);
if(execvp(argv[0], argv) < 0) {
perror(argv[0]);
exit(1);
}
}
else {
/* Wait for the child to finish */
waitpid(child_pid, &stat_loc, WUNTRACED);
}
free(user_input);
free(argv);
}
return 0;
}
char** create_argv(char* command) {
int argc = get_argc(command) + 1;
char* temp;
int i = 0;
char** argv = calloc(argc, sizeof(*argv));
if(argv == NULL) {
perror("Unable to parse command: could not allocate memory");
exit(1);
}
for(temp = strtok(command, ARG_SEP); temp != NULL;
temp = strtok(NULL, ARG_SEP)) {
argv[i] = temp;
i++;
}
/* Set last item in argv to NULL, since execvp requires it */
argv[i] = NULL;
return argv;
}
char* prompt() {
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
char* bname = basename(cwd);
char prompt[PATH_MAX + 5] = "";
strcat(prompt, bname);
strcat(prompt, PROMPT);
char* input = calloc(LINE_MAX, sizeof(*input));
if(input == NULL) {
perror("Unable to read command: could not allocate memory");
exit(1);
}
printf("%s", prompt);
fgets(input, LINE_MAX, stdin);
input[strcspn(input, "\r\n")] = '\0';
return input;
}
int get_argc(char* command) {
int argc = 0, word = 0;
char* command_iter = command;
do {
switch(*command_iter) {
case '\0':
case ' ':
case '\t': if(word) { word = 0; argc++; }
default: word = 1;
}
} while(*(command_iter++));
return argc;
}
int cd(char* path) {
return chdir(path);
}