Code:
#include "def.h"
#include <string.h>
#include <pwd.h>
#include <errno.h>
/*Prototypes*/
void changedir(char* dir);
void errorParser(int error,char* dir);
/*Main function used for printing an
endless loop of tsh: , it also does
a one of initialisation, then gets lines
of input and parses them to extract the commands
and their parameters*/
main (int argc,char** argv){
int i;
initcold();
for(;;){
initwarm();
if (getline()){
if (i = parse()){
if(argc > 1 && argv[1] != NULL)
execute(i,argv[1]);
else
execute(i,NULL);
}
}
}
}
initcold (void){
/*
signal(SIGINT, SIG_IGN);
signal (SIGOUIT, SIG_IGN);
*/
}
/*Initializes global vars,sets infd and outfd
file descriptors for each of the simple command
structures in the cmdlin[] array to default vals*/
initwarm(void){
int i;
backgnd = FALSE;
lineptr = line;
avptr = avline;
infile[0] = '\0';
outfile[0] = '\0';
append = FALSE;
for (i = 0; i<PIPELINE; ++i){
cmdlin[i].infd = 0;
cmdlin[i].outfd = 1;
}
for (i = 3; i<OPEN_MAX; ++i)
close(i);
printf("tsh: ");
fflush(stdout);
}
/*Takes characters from stdin and copies them into
the line[] array, until either a newline char or
MAXLINE number of chars have been entered*/
getline (void){
int i;
for (i = 0; (line[i] = getchar())!='\n' && i<MAXLINE; ++i);
if (i==MAXLINE){
fprintf(stderr, "Command line too long\n");
return(ERROR);
}
line[i+1] = '\0';
return (OKAY);
}
/*The parser must be
able to determine what is a command, what is a pipe,
what is a shell variable, what might the user expect
for command line completion etc.*/
parse (void){
int i;
/* 1 */
command(0);
/* 2 */
if (check("<"))
getname(infile);
/* 3 */
for (i = 1; i<PIPELINE; ++i)
if (check("|"))
command(i);
else
break;
/* 4 */
if (check(">")){
if (check(">"))
append = TRUE;
getname(outfile);
}
/* 5 */
if (check("&"))
backgnd = TRUE;
/* 6 */
if (check("\n"))
return(i);
else{
fprintf(stderr, "Command line syntax error\n");
return (ERROR);
}
}
/*Copies names of commands and their parameters
one word at a time from the line[] array to
the avline[] array. */
command(int i){
int j, flag, inword;
for (j = 0; j<MAXARG-1; ++j){
while (*lineptr==' ' || *lineptr=='\t')
++lineptr;
cmdlin[i].av[j] = avptr;
cmdlin[i].av[j+1] = NULL;
for (flag = 0; flag==0;){
switch (*lineptr){
case '>':
case '<':
case '|':
case '&':
case '\n':
if (inword==FALSE)
cmdlin[i].av[j] = NULL;
*avptr++ = '\0';
return;
case ' ':
case '\t':
inword = FALSE;
*avptr++ = '\0';
flag = 1;
break;
default:
inword = TRUE;
*avptr++ = *lineptr++;
break;
}
}
}
}
execute(int j,char* restricted){
int i, fd, fds[2];
/*If input redirection file specified*/
if (infile[0] !='\0')
cmdlin[0].infd = open(infile, O_RDONLY);
/*If output redirection file specified*/
if (outfile[0] !='\0')
if (append==FALSE)
cmdlin[j-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
else
cmdlin[j-1].outfd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
/*If command line to be run in background*/
if (backgnd==TRUE)
signal (SIGCHLD, SIG_IGN);
else
signal (SIGCHLD, SIG_DFL);
/* 4 */
for (i = 0; i <j; ++i){
/* 5 */
if (i<j-1){
pipe (fds);
cmdlin[i].outfd = fds[1];
cmdlin[i+1].infd = fds[0];
}
/*Creates child process to run simple command i*/
if(restricted == NULL)
forkexec(&cmdlin[i],NULL);
else
forkexec(&cmdlin[i],restricted);
/* 7 */
if ((fd = cmdlin[i].infd)!=0)
close(fd);
if ((fd = cmdlin[i].outfd)!=1)
close(fd);
}
/* 8 */
if (backgnd==FALSE)
while (wait (NULL) != lastpid);
}
/*The point of forkexec() is that the parent
process (the shell) is halted until the child
process (the command entered into the shell)
terminates.*/
forkexec(struct cmd *ptr,char* restricted){
int i,pid;
/*Fork child process, store id returned*/
if (pid = fork()){
/* 2 */
if (backgnd==TRUE)
printf("%d\n", pid);
lastpid = pid;
}
else{
/* 3 */
if (ptr->infd==0 && backgnd==TRUE)
ptr->infd = open("/dev/null", O_RDONLY);
/* 4 */
if (ptr->infd!=0){
close(0);
dup(ptr->infd);
}
if (ptr->outfd!=1){
close(1);
dup(ptr->outfd);
}
/* 5 */
if (backgnd==FALSE){
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
}
/* 6 */
for (i = 3; i<OPEN_MAX; ++i)
close(i);
/*This is where commands get executed
use execv by here to execute you own
code*/
if((strcmp(ptr->av[0],"ls")) == 0){
execv("ls.exe",ptr->av);
exit(1);
}else if((strcmp(ptr->av[0],"cd")) == 0){
if(restricted == NULL){
if(ptr->av[1] != NULL){
changedir(ptr->av[1]);
exit(1);
}else{
changedir(NULL);
exit(1);
}
}else{
if((strcmp(restricted,"--restricted")) != 0){
if(ptr->av[1] != NULL){
changedir(ptr->av[1]);
exit(1);
}else{
changedir(NULL);
exit(1);
}
}else{
fprintf(stderr,"Sorry restricted shell\n");
exit(1);
}
}
}else if((strcmp(ptr->av[0],"pwd")) == 0){
execv("pwd.exe",ptr->av);
exit(1);
}else if((strcmp(ptr->av[0],"kill")) == 0){
if(restricted == NULL){
execv("kill.exe",ptr->av);
exit(1);
}else{
if((strcmp(restricted,"--restricted")) != 0){
execv("kill.exe",ptr->av);
exit(1);
}else{
fprintf(stderr,"Sorry restricted shell\n");
exit(1);
}
}
}else if((strcmp(ptr->av[0],"ps")) == 0){
if(restricted == NULL){
execv("ps.exe",ptr->av);
exit(1);
}else{
if((strcmp(restricted,"--restricted")) != 0){
execv("ps.exe",ptr->av);
exit(1);
}else{
fprintf(stderr,"Sorry restricted shell\n");
exit(1);
}
}
}else{
printf("%s\n",ptr->av[0]);
execvp(ptr->av[0],ptr->av);
exit(1);
}
}
}
check(char *ptr){
char *tptr;
while (*lineptr== ' ' )
lineptr++;
tptr = lineptr;
while (*ptr!='\0' && *ptr==*tptr){
ptr++;
tptr++;
}
if (*ptr!='\0')
return(FALSE);
else{
lineptr = tptr;
return(TRUE);
}
}
getname(char *name){
int i;
for (i = 0; i<MAXNAME; ++i){
switch (*lineptr){
case '>':
case '<':
case '|':
case '&':
case ' ':
case '\n':
case '\t':
*name = '\0';
return;
default:
*name++ = *lineptr++;
break;
}
}
*name = '\0';
}
void changedir(char* dir){
uid_t me; /*Used to find the user id of user*/
struct passwd *user; /*Holds details about users home directory*/
if(dir != NULL){ /*If an argument is supplied change dir to the argument*/
if((errno = chdir(dir)) == ENOTDIR)
fprintf(stderr,"Can't change to %s\n",dir);
else
errorParser(errno,dir);
}else{ /*If no argument is supplied change to the users home dir*/
me = getuid(); /*Get the user id of the user*/
user = getpwuid(me); /*Get the user info based on the uid "me"*/
if(!user){
fprintf(stderr,"Couldn't find user %d\n",(int) me);
exit(1);
}
if((errno = chdir(user->pw_dir)) == ENOTDIR)
fprintf(stderr,"Can't change to %s\n",user->pw_dir);
else
errorParser(errno,user->pw_dir);
}
}
/*Deals with error occurences*/
void errorParser(int error,char* dir){
switch(error){
case EACCES:
fprintf(stderr,"Permission denied to %s\n",dir);
break;
case ENOENT:
fprintf(stderr,"No entry %s\n",dir);
break;
case EFAULT:
fprintf(stderr,"Outside allocated memory space: %s\n",dir);
break;
case EINTR:
fprintf(stderr,"Signal caught during execution of %s\n",dir);
break;
case EIO:
fprintf(stderr,"IO Error\n");
break;
case ELOOP:
fprintf(stderr,"Too many symbolic links %s\n",dir);
break;
case ENAMETOOLONG:
fprintf(stderr,"Name too long: %s\n",dir);
break;
case ENOLINK:
fprintf(stderr,"No link exists %s\n",dir);
break;
case ETIMEDOUT:
fprintf(stderr,"Timed out\n");
break;
case EMULTIHOP:
fprintf(stderr,"Multi hop not allowed\n");
break;
default:
printf("Changed to %s\n",dir);
break;
}
}