logoISU  

CS 456 - Systems Programming

Spring 2024

Displaying ./code/shell/shell.c

// a very basic shell

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

#define TOKBUF 64
#define TOKDELIM " \t\r\n\a"


//shell stuff
void run_shell(void);
char *readLine(void);
char **splitLine(char *line);
int launch(char **args);
int execute(char **args);

int num_builtins();

//shell commands
int shell_cd(char **args);
int shell_help(char **args);
int shell_exit(char **args);

char *builtin_str[] = {
  "cd",
  "help",
  "exit"
};


int (*builtin_func[]) (char **) = {
  &shell_cd,
  &shell_help,
  &shell_exit
};


int main(int argc, char **argv){

	//put config files here

	run_shell();

	//perform shutdown stuff here

	return 0;
}

void run_shell(void){

	//some declarations
	char *line;
	char **args;
	int status;

	do{

		printf("> ");
		line = readLine();
		args = splitLine(line);
		status = execute(args);

	} while(status);

}

char *readLine(void){

	char *line = NULL;
	ssize_t bufsize = 0;

	//getline allocates a buffer for us
	if(getline(&line, &bufsize, stdin) == -1){
		if (feof(stdin)){ //we hit EOF
			exit(0); 
		} else {
			perror("readLine");
			exit(-1);
		}
	}

	return line;
}

char **splitLine(char *line){

	int bufsize = TOKBUF;
	int position = 0;
	char **tokens = malloc(bufsize * sizeof(char*));
	char *token;

	if(!tokens){
		perror("splitLine: allocation error before while loop");
		exit(-1);
	}

	token = strtok(line, TOKDELIM);
	while(token != NULL){
		tokens[position] = token;
		position++;

		if(position >= bufsize){
			bufsize += TOKBUF;
			tokens = realloc(tokens, bufsize* sizeof(char*));
			if(!tokens){
				perror("splitLine: allocation error in while loop");
				exit(-1);
			}
		}
		token = strtok(NULL, TOKDELIM);
	}

	tokens[position] = NULL;
	return tokens;
}

int launch(char **args){

	pid_t pid, wpid;
	int status;

	pid = fork();

	if(pid == 0){
		//child process
		if (execvp(args[0], args) == -1){
			perror("execute: Error in Child Process");

		}
		exit(-1);

	} else if (pid < 0){
		perror("execute: Error forking");
	} else {
		//parent process
		do {
			wpid = waitpid(pid, &status, WUNTRACED);
		} while (!WIFEXITED(status) && !WIFSIGNALED(status));

	}

	return 1;
}


int num_builtins() {
  return sizeof(builtin_str) / sizeof(char *);
}


int shell_cd(char **args){

	if (args[1] == NULL) {
    	fprintf(stderr, "shell: expected argument to \"cd\"\n");
  	} else {
    	if (chdir(args[1]) != 0) {
      		perror("shell:");
    	}
  	}
  return 1;

}

int shell_help(char **args){

	printf("Current Builtins\n");

	for (int i = 0; i < num_builtins(); i++) {
	  printf("  %s\n", builtin_str[i]);
	}


}

int shell_exit(char **args){
	return 0;
}

int execute(char **args){
  
  int i;

  if (args[0] == NULL) {
    // An empty command was entered.
    return 1;
  }

  for (i = 0; i < num_builtins(); i++) {
    if (strcmp(args[0], builtin_str[i]) == 0) {
      return (*builtin_func[i])(args);
    }
  }

  return launch(args);	


}