FENIX_coreutils/sh.c

152 lines
3.2 KiB
C
Raw Normal View History

#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>
/*
Gods damn it, of course we have to have special shit
just for the fucking GNU Project. Fuckers can't let
anything be done to standard unless they fucking want
to or you beg them to let you, can they?
-Kat
*/
#ifdef __GLIBC__
#define __USE_POSIX
#define __USE_POSIX2
#endif
#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; /* 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) {
/* 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);
}