diff options
Diffstat (limited to 'userspace/fsh.c')
| -rw-r--r-- | userspace/fsh.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/userspace/fsh.c b/userspace/fsh.c new file mode 100644 index 0000000..4df4e4e --- /dev/null +++ b/userspace/fsh.c @@ -0,0 +1,320 @@ +/** + * @file + * + * Fool's Shell + * ========= + * + * A minimalsitic and naive shell developed along the Fool OS kernel. + * TODO: Free tokenizer / dynamic size! + * TODO: & with pipes + * TODO: > < + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <string.h> +#include "interface/fs.h" + +#include "newcalls.h" + +extern char **environ; + +bool process(char *buf); +bool metaprocess(char *buf); +bool cd(char *path); + +void version() +{ + puts("Fool's Shell version git-commit:" GIT_REVISION "\ncompiled on " __DATE__ " at " __TIME__); +} +void help() +{ + puts( "\nfoolshell: supported built-in commands/functions:\n\n" + + "'env' - show all environment variables\n" + "'getenv [var]' - show environment variable\n" + "'setenv [var] [val]' - set environemnet variable\n" + + "'cd [dir]' - change directory (set $PWD)\n" + "'[binary] [params...]' - run a binary\n" + "'[binary] [params...] &' - run a binary in background\n" + " | - pipes\n" + + "'help' - show this message\n" + "'exit' - exit running foolshell\n\n"); + +} + +void prompt() +{ + printf("\033[36mfool\033[37m@\033[32mhill\033[33m:%s%s\033[37m",getenv("PWD"),getenv("PS1")); +} + +int main(int argc, char **argv) +{ + for(int i=0;i<argc;i++) + { + if(!strcmp(argv[i],"--version")) + { + version(); + return 0; + } + + if(!strcmp(argv[i],"--help")) + { + help(); + return 0; + } + } + + char *buf=calloc(sizeof(char),256); + + // input and output without buffering + setvbuf(stdin,NULL,_IONBF,0); + setvbuf(stdout,NULL,_IONBF,0); + + printf("\033c"); // clear screen + + while(1) // process commands until exit + { + prompt(); + int bl=0; + + while(1) + { + char c=fgetc(stdin); + + if(c=='\b') + { + if(bl==0)continue; + buf[--bl]='\0'; + putc(c,stdout); + } + else + { + putc(c,stdout); + if(c=='\n')break; + buf[bl]=c; + buf[++bl]='\0'; + } + } + + if(!metaprocess(buf))break; // process input and return if exit + } + + return 0; +} + +// break the input in tokens on spaces +char **tokenize(char *buf,char chr) +{ + char **token; + token=malloc(10*sizeof(char*)); + token=realloc(token,20*sizeof(char*)); + + int l=strlen(buf); + + int i; + int c=0; + + for(i=0;i<l;i++) + { + // init space for next token + token[c]=malloc(256); + + //skip all the whitespace + while(buf[i]==chr&&i<l)i++; + if(i==l)break; + + //get token + int t=0; + + while(buf[i]!=chr&&i<l) + { + token[c][t]=buf[i]; + t++; + i++; + } + token[c][t]=0; + +// printf("token %i : <%s>\n",c, token[c]); + c++; + token[c]=NULL; + + } + return token; +} + +bool metaprocess2(char *buf); +bool metaprocess(char *buf) +{ + char **token=tokenize(buf,'|'); + if(token[0]==0 || token[1]==0)return process(buf); // no pipes + + int pid=_fork(); + + if(pid==0) + { + metaprocess2(buf); + exit(1); + } + + _wait(pid); + return true; +} + +bool metaprocess2(char *buf) +{ + char **token=tokenize(buf,'|'); + if(token[0]==0 || token[1]==0)return process(buf); // no pipes + + int fds[2]; + _pipe(fds); + + int pid=_fork(); + + if(pid==0) + { + // first child shall write to the pipe + _close(fds[0]); + _dup2(fds[1],1); // replace stdout with the write-end of our pipe + process(token[0]); + exit(1); + } + + _close(fds[1]); // and we read from it + _dup2(fds[0],0); + metaprocess2(strchr(buf,'|')+1); + + _wait(pid); + + return true; +} + +bool process(char *buf) +{ + char **token=tokenize(buf,' '); + char *command=token[0]; + + if(!strcmp(command,"help"))help(); + else if(!strcmp(command,"cd"))cd(token[1]); + else if(!strcmp(command,"exit")) return false; + //else if(!strcmp(command,"getenv"))printf("(0x%08X) get: '%s' = '%s'(0x%08X) \n",environ,token[1],getenv(token[1]),getenv(token[1])); + else if(!strcmp(command,"getenv"))printf("%s\n",getenv(token[1])); + else if(!strcmp(command,"setenv")) + { + sprintf(buf,"%s=%s",token[1],token[2]); + putenv(buf); + //printf("(0x%08X) set: '%s' = '%s' \n",environ,token[1],getenv(token[1])); + } + else if(!strcmp(command,"env")) + { + int i=0; +// printf("env: 0x%08X\n",environ); + while(environ[i]!=NULL) + { +// printf("envvar %s (0x%08X)\n" ,environ[i],environ[i]); + printf("%s\n" ,environ[i]); + i++; + } + } + else // otherwise treat command as exectutable and send to execve + { + int pid=_fork(); + + if(pid==0) + { + if(token[0][0]=='/')sprintf(buf,"%s",token[0]); + else sprintf(buf,"%s/%s",getenv("PATH"),token[0]); + _execve(buf,token,environ); + printf("foolshell: %s (errno: %d)\n",strerror(errno),errno); + exit(1); + } + + if(token[1]==NULL||strcmp(token[1],"&"))_wait(pid); + + } + return true; +} + +bool setpwd(char *path) +{ + if(!strcmp(path,"/")) + { + putenv("PWD=/"); + return true; + } + char buf[255]; + buf[0]=0; + strcat(buf,"PWD="); + + char **t=tokenize(path,'/'); + + char *p[100]; + int pp=0; + + while(*t!=NULL) + { + if(!strcmp(*t,"..")){ + pp--; + t++; + if(pp<0)pp=0; + continue; + } + if(!strcmp(*t,".")){t++; continue;} + if(**t!=0) + { + p[pp]=*t; + //printf("> %s\n",p[pp]); + pp++; + } + t++; + } + + if(pp==0) + { + strcat(buf,"/"); + } + + for(int i=0;i<pp;i++) + { + strcat(buf,"/"); + strcat(buf,p[i]); + } + + putenv(buf); + return true; // TODO check if dir exists at all. +} + +bool cd(char *path) +{ + char buf[256]; + // home + if(path==NULL) + { + sprintf(buf,"%s",getenv("HOME")); + } + // absolute + else if(path[0]=='/') + { + sprintf(buf,"%s",path); + } + // relative + else + { + sprintf(buf,"%s/%s",getenv("PWD"),path); + } + + // check if exists + fs_dirent dirs; + if(-1==_readdir(buf,&dirs,0)) + { + printf("directory not found!\n"); + return false; + } + + return setpwd(buf); +} |
