129 lines
2.6 KiB
C
129 lines
2.6 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <linux/limits.h>
|
||
|
#include <signal.h>
|
||
|
#include <libgen.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; //The command with arguments
|
||
|
char* user_input;
|
||
|
pid_t child_pid;
|
||
|
int stat_loc; //??? (Needed for waitpid)
|
||
|
|
||
|
signal(SIGINT, SIG_IGN); //Tell vsh to ignore SIGINT (^C)
|
||
|
|
||
|
while(1) {
|
||
|
user_input = prompt();
|
||
|
argv = create_argv(user_input);
|
||
|
|
||
|
if(strcmp(argv[0], "cd") == 0) {
|
||
|
if(cd(&user_input[3]) < 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) {
|
||
|
//If the child couldn't run, assume no memory
|
||
|
perror("Out of memory");
|
||
|
exit(1);
|
||
|
}
|
||
|
else if(child_pid == 0) {
|
||
|
//If we are the child, allow ^C
|
||
|
signal(SIGINT, SIG_DFL);
|
||
|
if(execvp(argv[0], argv) < 0) {
|
||
|
perror(argv[0]);
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
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) {
|
||
|
//If couldn't allocate argv, assume no memory
|
||
|
perror("Out of 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(512, sizeof(*input));
|
||
|
if(input == NULL) {
|
||
|
//If input allocate failed, assume no memory
|
||
|
perror("Out of memory");
|
||
|
exit(1);
|
||
|
}
|
||
|
printf("%s", prompt);
|
||
|
fgets(input, 512, stdin);
|
||
|
//Is 512 enough? What about really long commands?
|
||
|
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);
|
||
|
}
|