140 lines
3 KiB
C
Executable file
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);
|
|
}
|