Created
March 6, 2012 10:38
-
-
Save yeban/1985622 to your computer and use it in GitHub Desktop.
Implementing a shell. External commands, builtins, I/O redirection, and pipes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> //realloc() | |
#include <unistd.h> //fork(), pipe() | |
#include <limits.h> //PATH_MAX | |
//#include <sys/stat.h> | |
//#include <sys/types.h> | |
#include <fcntl.h> //access mode constants, and flags for open() | |
#include <errno.h> //errno | |
#include <readline/readline.h> | |
#include <readline/history.h> | |
#include <signal.h> | |
#define HISTFILE "./.history" | |
int noa; | |
int TO_BACKGROUND; | |
/* | |
* === FUNCTION ====================================================================== | |
* Name: parsecommand | |
* Description: Take the command string and parse it to create the arguments required | |
* to invoke execvp | |
* ===================================================================================== | |
*/ | |
char** parsecommand ( char *command ) { | |
char *buffer; | |
char **args; | |
int last = 0; | |
char *tokens = " "; | |
//start tokenising | |
buffer = strtok( command, tokens); | |
//obtain memory to store a pointer to the word and store it to args | |
size_t size = sizeof( buffer ); | |
args = malloc( size ); | |
args[last++] = buffer; | |
//do {} while, makes sure that a null pointer is added to the args | |
do{ | |
buffer = strtok( NULL, tokens) ; | |
size += size; | |
args = realloc( args, size ); | |
args[last++] = buffer; | |
}while( buffer != NULL ); | |
noa = --last; | |
return args; | |
} /* ----- end of function parsecommand ----- */ | |
/* | |
* === FUNCTION ====================================================================== | |
* Name: find | |
* Description: Takes an array of character pointers and returns the index of the first | |
* occurence of a string. Assumes the last element of the array to be NULL. | |
* ===================================================================================== | |
*/ | |
int find ( char **args, const char *to_find ) | |
{ | |
int i; | |
for( i = 0; args[ i ] != NULL; i++) | |
if( !strcmp( args[ i ], to_find ) ) | |
return i; | |
return 0; | |
} /* ----- end of function find ----- */ | |
/* | |
* === FUNCTION ====================================================================== | |
* Name: substr | |
* Description: Take a string and number of elements and return a substring of that length. | |
* ===================================================================================== | |
*/ | |
char* substr( const char *str, int elements ){ | |
char *sub = malloc( ( elements * sizeof( char ) ) + 1 ); | |
strncpy( sub, str, elements ); | |
sub[elements] = '\0'; | |
return sub; | |
} | |
/* | |
* === FUNCTION ====================================================================== | |
* Name: strcpya | |
* Description: Allocates required memory and then copies the src to the dest. | |
* ===================================================================================== | |
*/ | |
char* strcpya ( const char *src ) | |
{ | |
char *dst = malloc( ( strlen( src ) + 1 ) * sizeof( char ) ); //length + \0 | |
strcpy(dst, src); | |
return ; | |
} /* ----- end of function strcpya ----- */ | |
char** getargc ( char **args ) { | |
int rid; | |
if( ( rid = find( args, "<" ) ) || | |
( rid = find( args, ">" ) ) || | |
( rid = find( args, ">>") ) | |
){ | |
int i; | |
char **argc = malloc( rid * sizeof(char*) ); | |
for( i = 0; i < rid; i++ ){ | |
argc[ i ] = args[ i ]; | |
} | |
argc = realloc( argc, rid * sizeof( char* ) + 1 ); | |
argc[ i ] = NULL; | |
return argc; | |
} | |
return args; | |
} /* ----- end of function getargc ----- */ | |
char*** separate_piped_commands(char **args, int *no_of_piped_commands) | |
{ | |
//printf("in separate, argscount is %d, args[0] is %s,", argscount, args[0]); | |
char*** piped_commands = (char*** )malloc(5 * sizeof(char**)); | |
int k = 0; | |
int i,j=0; | |
piped_commands[k] = (char** ) malloc(20 * sizeof(char*)); | |
//printf("in separate, argscount is %d, args[0] is %s, k is", argscount, args[0], k); | |
for (i = 0; args[i] != NULL; i++) | |
{ | |
if (strcmp(args[i], "|") == 0) | |
{ | |
k++; | |
j=0; | |
piped_commands[k] = (char** ) malloc(20 * sizeof(char*)); | |
} | |
else | |
{ | |
piped_commands[k][j] = (char* )malloc(100 *sizeof(char)); | |
strcpy(piped_commands[k][j], args[i]); | |
j++; | |
} | |
} | |
//printf("%s",piped_commands[0][0]); | |
//printf("%s",piped_commands[0][1]); | |
*no_of_piped_commands = k; | |
return piped_commands; | |
} /* ----- end of function separate_piped_commands ----- */ | |
void recursive_pipes(char*** piped_commands, int no_of_pipes_left) | |
{ | |
// //ps | sort | less | |
if (no_of_pipes_left < 0) | |
{ | |
return; | |
} | |
int fds[2]; | |
pipe(fds); | |
int pid = fork(); | |
if (pid == 0) | |
{ | |
printf("hi"); | |
close(1); | |
dup(fds[1]); | |
close(fds[0]); | |
recursive_pipes(piped_commands, no_of_pipes_left - 1); | |
close(fds[1]); | |
execvp(piped_commands[no_of_pipes_left - 1][0], piped_commands[no_of_pipes_left - 1]); | |
} | |
else if (pid > 0) | |
{ | |
if (no_of_pipes_left > 0) | |
{ | |
close(0); | |
dup(fds[0]); | |
} | |
close(fds[1]); | |
wait(NULL); | |
close(fds[0]); | |
execvp(piped_commands[no_of_pipes_left][0], piped_commands[no_of_pipes_left]); | |
perror("Command not found"); | |
} | |
return; | |
} /* ----- end of function recursive_pipe ----- */ | |
void sigint_handler( ){ | |
signal( SIGINT, sigint_handler ); | |
} | |
int main(){ | |
//set signals | |
signal( SIGINT, sigint_handler ); | |
//shell builtins | |
char *builtin[] = { "pwd", "cd" }; | |
char *command = NULL; | |
//initialize readline's history session | |
using_history(); | |
if( read_history( HISTFILE ) ){ //error reading history file | |
if( errno == ENOENT ){ //file not found | |
//silently create one | |
open( HISTFILE, O_CREAT | O_RDWR, 0644 ); | |
} | |
else{ //other error | |
//simply display it | |
perror( "Error reading history file" ); | |
} | |
} | |
//accept input till 'exit' | |
while( 1 ){ | |
//read from the standard input | |
command = readline( "$ " ); | |
if( !command ){ //EOF | |
write_history( HISTFILE ); //save the history | |
exit( EXIT_SUCCESS ); | |
} | |
else if( !*command ){ //blank line | |
continue; //move to next iteration | |
} | |
else{ //text entered | |
add_history( command ); //add it to the history | |
} | |
if( strcmp( command, "exit" ) ){ | |
write_history( HISTFILE ); //save the history | |
exit( EXIT_SUCCESS ); | |
} | |
else{ | |
int background = is_background( command ); | |
pid_t pid = fork(); | |
if( pid == 0 ){//in child | |
} | |
else{ //in parent | |
} | |
} | |
} | |
} | |
int is_background( char* command ){ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment