Written in C
#define _POSIX_SOURCE #define _BSD_SOURCE #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <stdlib.h>//malloc #include <stdio.h> #include <errno.h> #define SIZE 1024 char USAGE[]="Usage: $EggShell seconds"; int string_to_int(char* input);//convert a string to int. when encounter a non-number, the rest of the string is ignored void print_prompt();//print the shell prompt void print_int(int num);//print an integer to the monitor void print_string(char* input);//print a string, ended with NULL, to the monitor void print_cr();//print to monitor carrage return/new line char** command_parser(char* input, int* output_length);//the input string is parsed by space, ' ', to substrings stored in output. //the length of the string array returned: output_length is recorded. The caller is responsible to free the memory using command_parser_free() void command_parser_free(char** string_array, int length); int read_terminal(char* buf);//if the string is ended with a carrige return, common for termial input, it is parsed to end with 0. //return the actually string length int run_command(char** command,int time_out); void alarm_handler(int signum); /****************************************/ int main(int argc, char** argv){ int time_out = 1;//second if (argc != 2){ print_string(USAGE); print_cr(); if (argc > 2) return 0; } else time_out = string_to_int(argv[1]); char read_buff[SIZE+1]; read_buff[SIZE] = 0; while(1){ print_prompt(); int read_length = read(STDIN_FILENO, read_buff, SIZE);// read_terminal(read_buff); if (read_length && '\n'==read_buff[0]) continue;//only Enter is pressed if (read_length && '\n'==read_buff[read_length-1]) --read_length; read_buff[read_length] = 0;//terminate string int fork_id = fork(); if (fork_id < 0){ print_string("Fork failed!\n"); }else if(fork_id > 0){//parent int status; wait(&status);//man wait for the use of status if(WIFSIGNALED(status)){ print_string("All eggs are hatched! You need another shell!\n"); } else if (WIFEXITED(status)){ if (EXIT_EGGSHELL == WEXITSTATUS(status)){ print_string("Exit\n"); return 0; } else if (COMMAND_ERROR != WEXITSTATUS(status)) print_string("You escaped, for now!\n"); } }else{//child int vector_length = 0; char** string_vector = command_parser(read_buff, &vector_length); if (!string_vector || !string_vector[0]){ _exit(EXIT_EGGSHELL);//input is ctrl+d only } run_command(string_vector, time_out); command_parser_free(string_vector, vector_length); //int errsv = errno; perror("Command Error"); _exit(COMMAND_ERROR); //exit with a command error }//eles child }//for ii }//main() /***************************************/ int string_to_int(char* input){ int result = 0; for(int ii = 0; input[ii] >= '0' && input[ii] <='9'; ++ii){ result *= 10; result += input[ii]-'0'; }//for ii return result; }//string_to_int() void print_prompt(){ char prompt[]="$EggShell>"; print_string(prompt); } void print_int(int num){ if (!num) return; char digit = num % 10 + '0'; print_int(num/10); write(STDOUT_FILENO,&digit,1); }//print_int() void print_string(char* input){ if(!input) return; for(int ii = 0; input[ii] != 0; ++ii){ write(STDOUT_FILENO,&input[ii],1); }//for ii }//print_string() void print_cr(){ write(STDOUT_FILENO,"\n",1); }//print_cr char** command_parser(char* input, int* output_length){ *output_length = 0; char** v_string = (char**)malloc(128*sizeof(char*));//max number of arguments for(int ii = 0; input[ii]; ){//whole string while (input[ii] == ' ') ++ii; if (!input[ii]) break; char* a_string = (char*)malloc(128*sizeof(char));//max length of an argument int jj = 0;//index for a word while ( input[ii] && input[ii] != ' '){ a_string[jj++] = input[ii++]; } a_string[jj++] = 0;//string end a_string = realloc(a_string, jj*sizeof(char*));//reszie (shrink) word string v_string[(*output_length)++] = a_string;//careful, ++ is higher than * }//for ii v_string[(*output_length)++] = NULL; v_string = realloc(v_string, *output_length*(sizeof(char*))); return v_string; }//command_parser() void command_parser_free(char** string_array, int length){ for(int ii = 0; ii < length; ++ii) free(string_array[ii]); free(string_array); } int read_terminal(char* buf){ int read_in = read(0, buf, SIZE); if (read_in && buf[read_in-1] == 10){//10 is new line feed --read_in; } buf[read_in] = 0; return read_in; } int run_command(char** command, int time_out){ alarm(time_out); signal(SIGALRM, alarm_handler); return execve(command[0],command,NULL); } void alarm_handler(int signum){//p268 kill(getpid(),SIGKILL); }/****************END********************/
No comments:
Post a Comment