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