// 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 30
const 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 command
int 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;
}