Skip to content

Commit

Permalink
Add support for PATH and other environment variables
Browse files Browse the repository at this point in the history
Also, the shell prompt now has color
  • Loading branch information
DanielVukelich committed Nov 13, 2016
1 parent fe1282d commit 58e1b01
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 73 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CC=gcc
CFLAGS=-Wall -Werror -std=c99
OBJS= err_handling.o trie/trie.o trie/intern.o builtin.o argbuild.o vsh.o
CFLAGS=-pedantic -Wall -Wextra -Werror -std=c99
OBJS=err_handling.o trie/trie.o trie/intern.o builtin.o argbuild.o vsh.o envmgr.o
BINARY=vsh

.PHONY: clean all debug release
Expand Down
5 changes: 4 additions & 1 deletion builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <unistd.h>
#include <string.h>

#include "envmgr.h"
#include "vsh.h"
#include "trie/trie.h"

Expand All @@ -17,7 +18,7 @@ typedef struct func_ary_elt{
char* cmd_name;
} func_ary_elt_t;

int shell_exit(int argc, char** argv){
int shell_exit(__attribute__((unused))int argc, __attribute__((unused))char** argv){
running = 0;
return 0;
}
Expand All @@ -33,6 +34,8 @@ int change_directory(int argc, char** argv){
last_cmd_errno = errno;
if(toreturn){
errstr = strerror(last_cmd_errno);
}else{
update_pwd();
}
return toreturn;
}
Expand Down
78 changes: 78 additions & 0 deletions envmgr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "envmgr.h"

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/limits.h>

static char* pwd;
static char* old_pwd;

static char prog_path[PATH_MAX];

//The compiler throws a hissyfit if setenv doesn't have a function declaration
//here, despite the fact that it *IS* in stdlib.h which *IS* #include'd
int setenv(const char*, const char*, int);

void init_envmgr(){
pwd = malloc(sizeof(char) * PATH_MAX);
if(getcwd(pwd, PATH_MAX) != pwd){
pwd[0] = '\0';
}
old_pwd = malloc(sizeof(char) * PATH_MAX);
}

void deinit_envmgr(){
free(pwd);
free(old_pwd);
}

const char* get_pwd(){
return pwd;
}

void update_pwd(){
strncpy(old_pwd, pwd, PATH_MAX);
if(getcwd(pwd, PATH_MAX) != pwd){
pwd[0] = '\0';
}
setenv("PWD", pwd, 1);
setenv("OLDPWD", old_pwd, 1);
}

void execute_program(char* program, char** arguments){
//Try to execute the program in all the paths found in $PATH
//But first, try to execute it in the current directory
execv(program, arguments);
//If we return from an execv call, it failed
char* pathstr = getenv("PATH");

if(!pathstr)
return;

char* begincolon = pathstr;
char* endcolon = NULL;
do{
if(*pathstr == ':' || *pathstr == '\0'){
endcolon = pathstr;
int size = endcolon - begincolon;
strncpy(prog_path, begincolon, size);
//Add a slash to the end of the path before concatenating
//our command string
prog_path[size] = '/';

//Now add our command to the end
char* cat_begin = (prog_path + size + 1);
//don't let anyone copy past the end of the array
size = PATH_MAX - size - 1;
strncpy(cat_begin, program, size);

//Now try to run the program from that location
execv(prog_path, arguments);
begincolon = endcolon + 1;

}
}while(*(pathstr++) != '\0');

//If we get to here, then the command could not be found
}
14 changes: 14 additions & 0 deletions envmgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef ENVIRONMENT_MANAGER_H
#define ENVIRONMENT_MANAGER_H

#include <stdlib.h>

void init_envmgr();
void deinit_envmgr();

void update_pwd();
const char* get_pwd();
void execute_program(char* program, char** arguments);


#endif
143 changes: 73 additions & 70 deletions vsh.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,84 @@
#include <sys/wait.h>
#include <assert.h>

#include "envmgr.h"
#include "argbuild.h"
#include "builtin.h"
#include "err_handling.h"

#define DIR_STR_SIZ 1024
#define RED "\x1B[31m"
#define GRN "\x1B[32m"
#define YEL "\x1B[33m"
#define BLU "\x1B[34m"
#define MAG "\x1B[35m"
#define CYN "\x1B[36m"
#define WHT "\x1B[37m"
#define RESET "\x1B[0m"

int main(int __attribute__((unused))argc, char** argv){
me = argv[0];
running = 1;

const long ARG_MAX = sysconf(_SC_ARG_MAX);
char* cmdbuf = malloc(sizeof(char) * ARG_MAX);
//This holds all the args that a child could be passed.
//ARG_MAX is the maximum length of an argument, so there
//can never be more than ARG_MAX/2 arguments (assuming there
//are ARG_MAX arguments of 1 char each separated by spaces)
char** child_argv = malloc(sizeof(char) * (ARG_MAX / 2));
last_argv = child_argv;

char user_prompt = '$';
if(geteuid() == 0)
user_prompt = '#';

init_builtin_commands();
init_envmgr();

puts("Welcome to vsh, the Vukelich Shell.\n");

while(running){

printf(CYN "%s %c " RESET, get_pwd(), user_prompt);

if(fgets(cmdbuf, ARG_MAX, stdin) != cmdbuf){
puts("");
running = 0;
continue;
}

arg_t* args = build_args(cmdbuf, ARG_MAX);

//Get our argc and fill our argv
int child_argc = get_args(args, child_argv);

//See if the command we've been given should be
//executed internally. If not, assume it's a
//program
run_builtin_command(child_argc, child_argv);
if(!builtin_cmd_found){
if(!fork()){
execute_program(child_argv[0], child_argv);
printf("%s: %s: Command not found\n", me, child_argv[0]);
return 1;
}
wait(NULL);
}

//If the user ran a command built in to the shell
//(like cd), and it had an error, print that error
if(builtin_cmd_found && last_cmd_code){
print_error();
}

free_args(args);

int main(int argc, char** argv, char** envp){
me = argv[0];
running = 1;
char pwd[DIR_STR_SIZ];
const long ARG_MAX = sysconf(_SC_ARG_MAX);
char* cmdbuf = malloc(sizeof(char) * ARG_MAX);
//This holds all the args that a child could be passed.
//ARG_MAX is the maximum length of an argument, so there
//can never be more than ARG_MAX/2 arguments (assuming there
//are ARG_MAX arguments of 1 char each separated by spaces)
char** child_argv = malloc(sizeof(char) * (ARG_MAX / 2));
last_argv = child_argv;

char user_prompt = '$';
if(geteuid() == 0)
user_prompt = '#';

init_builtin_commands();

puts("Welcome to vsh, the Vukelich Shell.\n");


while(running){

//Get the current working directory. If an error occurs, then
//set the pwd string to empty
if(getcwd(pwd, DIR_STR_SIZ) != pwd){
pwd[0] = '\0';
}
puts("Exiting");
free(cmdbuf);
free(child_argv);
deinit_builtin_commands();
deinit_envmgr();

printf("%s %c ", pwd, user_prompt);

if(fgets(cmdbuf, ARG_MAX, stdin) != cmdbuf){
puts("");
running = 0;
continue;
}

arg_t* args = build_args(cmdbuf, ARG_MAX);

//Get our argc and fill our argv
int child_argc = get_args(args, child_argv);

//See if the command we've been given should be
//executed internally. If not, assume it's a
//program
run_builtin_command(child_argc, child_argv);
if(!builtin_cmd_found){
if(!fork()){
execve(child_argv[0], child_argv, envp);
printf("%s: %s: Command not found\n", me, child_argv[0]);
return 1;
}
wait(NULL);
}

//If the user ran a command built in to the shell
//(like cd), and it had an error, print that error
if(builtin_cmd_found && last_cmd_code){
print_error();
}

free_args(args);

}
puts("Exiting");
free(cmdbuf);
free(child_argv);
deinit_builtin_commands();

return 0;
return 0;
}

0 comments on commit 58e1b01

Please sign in to comment.