223 lines
No EOL
4.7 KiB
C
Executable file
223 lines
No EOL
4.7 KiB
C
Executable file
#define _XOPEN_SOURCE 700
|
|
|
|
#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);
|
|
int get_argc_argv(char * argv[]);
|
|
char* prompt();
|
|
int cd(char* path);
|
|
int _kill(int argc, char * argv[]);
|
|
|
|
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], "kill") == 0) {
|
|
_kill(get_argc_argv(argv), argv);
|
|
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 get_argc_argv(char * argv[]) {
|
|
int argc = 0;
|
|
while(argv[argc] != NULL) {
|
|
argc++;
|
|
}
|
|
return argc;
|
|
}
|
|
|
|
int cd(char* path) {
|
|
return chdir(path);
|
|
}
|
|
|
|
int get_signum(char * signame) {
|
|
if(strcmp(signame, "SIGHUP") == 0) {
|
|
return 1;
|
|
}
|
|
else if(strcmp(signame, "SIGINT") == 0) {
|
|
return 2;
|
|
}
|
|
else if(strcmp(signame, "SIGQUIT") == 0) {
|
|
return 3;
|
|
}
|
|
else if(strcmp(signame, "SIGABRT") == 0) {
|
|
return 6;
|
|
}
|
|
else if(strcmp(signame, "SIGKILL") == 0) {
|
|
return 9;
|
|
}
|
|
else if(strcmp(signame, "SIGALRM") == 0) {
|
|
return 14;
|
|
}
|
|
else if(strcmp(signame, "SIGTERM") == 0) {
|
|
return 15;
|
|
}
|
|
}
|
|
|
|
int _kill(int argc, char * argv[]) {
|
|
int signal = 0; pid_t pid; char c;
|
|
int write_signame = 0, error = 0;
|
|
|
|
while((c = getopt(argc, argv, "s:l")) != -1) {
|
|
switch(c) {
|
|
case 's': signal = get_signum(optarg); break;
|
|
case 'l': write_signame = 1; break;
|
|
}
|
|
}
|
|
|
|
if(signal == 0 && argv[1][0] == '-' && write_signame == 0) {
|
|
if(argv[1][1] >= '0' && argv[1][1] <= '9') {
|
|
signal = atoi((argv[1])+1);
|
|
}
|
|
else {
|
|
signal = get_signum((argv[1])+1);
|
|
}
|
|
}
|
|
|
|
if(write_signame) {
|
|
if(argc > 2) {
|
|
/* TODO: Figure out how to get exit status from $? */
|
|
}
|
|
else {
|
|
printf("SIGHUP\n");
|
|
printf("SIGINT\n");
|
|
printf("SIGQUIT\n");
|
|
printf("SIGABRT\n");
|
|
printf("SIGKILL\n");
|
|
printf("SIGALRM\n");
|
|
printf("SIGTERM\n");
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
for(int i = optind; i < argc && argv[i] != NULL; i++) {
|
|
pid = atoi(argv[optind]);
|
|
if(kill(pid, signal) != 0) {
|
|
error = 1;
|
|
}
|
|
}
|
|
}
|
|
} |