// author OBLiQUE// copyleft 2009// simple unix shell skeleton// p0wnbox.com#include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <unistd.h>#include <signal.h>#include <sys/utsname.h>#include <sys/wait.h>#define MAX_STRING 0xfff#define MAX_ARGS 30const char *shell_commands[] = {"cd","exit","\0"};void print_prompt();int chk_sh_cmds(char *str, char **tok);void sig_int(const int sig_num);int main(int argc, char *arg[]){ char *tok, buf[MAX_STRING], *args[MAX_ARGS+1]; int readlen, sh_cmd_num, arg_num, status; pid_t pid; // register SIGINT signal handler to disable ctrl+c if (signal(SIGINT,sig_int)==SIG_ERR) fprintf(stderr,"Error! cannot register signal handler!\n"); print_prompt(); while (readlen=read(STDIN_FILENO,buf,MAX_STRING)) { // read the line and return the length buf[readlen-1]='\0'; // remove \n from the end if (sh_cmd_num=chk_sh_cmds(buf,&tok)) { // check if its a shell command switch (sh_cmd_num) { case 1: // cd chdir(tok); // change directory break; case 2: // exit printf("exit\n"); exit(EXIT_SUCCESS); } } else { // if it's not a shell command tok=strtok(buf," "); // replace the first space with '\0' and take the tokken arg_num=0; // initiliaze the arg_num while (tok!=NULL && arg_num<MAX_ARGS) { // repeat until the end of string or until the MAX_ARGS args[arg_num]=tok; // put the tokken to the array arg_num++; // increase the arg_num tok=strtok(NULL," "); // replace the next space with '\0' and take the tokken } args[arg_num]=NULL; // fill with NULL the last empty argument if (args[0]!=NULL) { // i there is a command to execute if ((pid=fork())<0) { // fork a child and check if it's forked fprintf(stderr,"Error! cannot fork child!\n"); exit(EXIT_FAILURE); } else if (pid==0) { // if i'm the child execvp(args[0],args); // execute the command // the exec replace its memory with command that executes // so if i get this error means that exec failed fprintf(stderr,"Error! cannot execvp command: %s\n",args[0]); exit(EXIT_FAILURE); // child exit } // i'm the parent if ((pid=waitpid(pid,&status,0)<0)) // wait the child to exit fprintf(stderr,"Error! cannot wait for child!\n"); } } print_prompt(); } // end of while}void sig_int(const int sig_num){ printf("\n"); print_prompt();}void print_prompt(){ struct utsname s_uname; // uname structure char path[PATH_MAX], symbol, *login_name, *dir_name; if (getuid()) symbol='$'; // if uid!=0 the symbol is $ else symbol='#'; // otherwise is # uname(&s_uname); // retrieve system information login_name=getlogin(); // retrieve login username getcwd(path,PATH_MAX); // retrieve path dir_name=strrchr(path,'/'); // find the directory name printf("%s@%s %s/ %c ",login_name,s_uname.nodename,++dir_name,symbol); fflush(stdout); // force to write the buffered data to stdout}// this function returns 0 if the command is not a shell command// otherwise returns the index of the shell commandint chk_sh_cmds(char *str, char **tok){ if (str[0]=='\0') return 0; // if the string is null return 0 strtok_r(str," ",tok); // find the first space and replace it with '\0' int i; for (i=0; shell_commands[i][0]!='\0'; i++) // loop until the end of array if (!strcmp(str,shell_commands[i])) return i+1; // i is a shell command return i+1 if (*((*tok)-1)=='\0') *((*tok)-1)=' '; // restore the space return 0;}