Thread: cd aint cd'ing

  1. #1
    Registered User
    Join Date
    Mar 2002
    Posts
    87

    cd aint cd'ing

    Ok i've written some code which implements the cd command. Problem is it doesn't actually seem to change the directory at all. It says it has but when u do a pwd ur still in the same directory!!! WHY???????????????

    Code:
    /*The following code will implement the*
     *cd (change directory) command in UNIX.*/
    #include <pwd.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main(int argc,char **argv){
      uid_t me;
      struct passwd *user;
      if(argc>1 && argv[1] != NULL){
        if((errno = chdir(argv[1])) == ENOTDIR){
          fprintf(stderr,"Can't change to %s\n",argv[1]);
          return -1;
        }else
    	  printf("Changed to %s\n",argv[1]);
      }else{
        me = getuid();
        user = getpwuid(me);
        if(!user){
          fprintf(stderr,"Couldn't find user %d\n",(int) me);
          exit(EXIT_FAILURE);
        }
        if((errno = chdir(user->pw_dir)) == ENOTDIR){
          fprintf(stderr,"Can't change to %s\n",user->pw_dir);
          return -1;
        }else
    	  printf("Changed to %s\n",user->pw_dir);
      }
      return EXIT_SUCCESS;
    }
    PuterPaul.co.uk - Portfolio site

  2. #2
    The Artful Lurker Deckard's Avatar
    Join Date
    Jan 2002
    Posts
    633
    Scope.

    Let's say you are in your home directory (/home/pdstatha), and you execute a program. The program makes a call to chdir and you end up at /etc. Now /etc is the working directory for the application. When the application ends, its resources are reclaimed by the OS and you are returned to your shell, which is way back in /home/pdstatha.
    Jason Deckard

  3. #3
    Registered User
    Join Date
    Mar 2002
    Posts
    87
    So is there a way for it not to do that???????
    PuterPaul.co.uk - Portfolio site

  4. #4
    The Artful Lurker Deckard's Avatar
    Join Date
    Jan 2002
    Posts
    633
    No. This is why the cd command is built into the shell, and not a stand alone program.
    Jason Deckard

  5. #5
    Registered User
    Join Date
    Mar 2002
    Posts
    87
    Ok by your logic, If I had written a shell myself and coded cd into the shell then It should work. Well here goes, heres the shell plus cd coded into it. It still doesn't work tho!!!

    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;
    	}
    }
    PuterPaul.co.uk - Portfolio site

  6. #6
    The Artful Lurker Deckard's Avatar
    Join Date
    Jan 2002
    Posts
    633
    Well, if we're gonna do this we might as well go all the way. Send me your def.h file so I can compile this and step through it with the debugger.
    Jason Deckard

  7. #7
    Registered User
    Join Date
    Mar 2002
    Posts
    87
    Ok here's the code for the def.h

    Code:
    #include <stdio.h>
    #include <limits.h>
    #include <signal.h>
    #include <fcntl.h>
    
    #define TRUE     1
    #define FALSE    0
    #define OKAY     1
    #define ERROR    0
    #define MAXLINE  200    /*Max length of input line*/
    #define MAXARG   20     /*Max number of args for simple command*/
    #define PIPELINE 5      /*Max commands in simple pipeline*/
    #define MAXNAME  100    /*Max length of i/o redirection filename*/
    
    char line[MAXLINE+1];   /*User typed input line*/
    char *lineptr;          /*Pointer to current position in line[]*/
    char avline[MAXLINE+1]; /*Argv strings taken from line[]*/
    char *avptr;            /*Pointer to current position in avline[]*/
    char infile[MAXNAME+1]; /*Input redirection filename*/
    char outfile[MAXNAME+1];/*Output redirection filename*/
    
    int backgnd;            /*TRUE if & ends pipeline else FALSE*/
    int lastpid;            /*PID of last simple command in pipeline*/
    int append;             /*TRUE for append redirection (>>) else FALSE*/
    
    struct cmd{
      char *av[MAXARG];
      int infd;
      int outfd;
    } cmdlin[PIPELINE];     /*Argvs and fds one per simple command*/
    PuterPaul.co.uk - Portfolio site

  8. #8
    The Artful Lurker Deckard's Avatar
    Join Date
    Jan 2002
    Posts
    633
    You seem to have the same problem: scope.

    Your application forks a child process, and the child process calls your changedir() function. This does not change the current working directory of the parent. Instead of forking to execute every command, consider handling the command locally unless it is unrecognized and then fork.

    HTH,
    Jason Deckard

  9. #9
    Registered User
    Join Date
    Mar 2002
    Posts
    87
    Ok this where my relative lack of experience starts to show, what you just said kinda made sense, unfortunately i'm not really sure how to begin doing that, do you have any suggestions. Or perhaps some code snippets to get me started?????
    PuterPaul.co.uk - Portfolio site

  10. #10
    The Artful Lurker Deckard's Avatar
    Join Date
    Jan 2002
    Posts
    633
    This should get you started:
    Code:
    #include <errno.h>
    #include <limits.h>
    #include <stdio.h>
    #include <unistd.h>
    
    #define COMMAND_LINE_MAX  1024
    
    int main( void )
    {
      char    CommandLine[COMMAND_LINE_MAX + 1];
      char   *cptr;
      char    CurrentDirectory[PATH_MAX + 1];
      int     Result;
      int     StayAlive = 1;
    
      while (StayAlive)
      {
        /* Wipe contents of CommandLine */
    
        memset( CommandLine, 0, COMMAND_LINE_MAX + 1 );
    
    
        /*
         *  Show a simple prompt that includes
         *  the current working directory.
         */
    
        if ( !getcwd( CurrentDirectory, PATH_MAX ) )
        {
          perror( "getcwd()" );
          break;
        }
    
        printf( "%s>", CurrentDirectory );
    
    
        /*
         *  Get the command.
         */
    
        if ( !fgets( CommandLine, COMMAND_LINE_MAX, stdin ) )
        {
          perror( "fgets()" );
          break;
        }
    
        /* Strip trailing carriage return */
    
        cptr = (char *) strchr( CommandLine, '\n' );
        if ( cptr )
          *cptr = 0;
    
    
        /*
         *  We know how to do two things, and
         *  are NOT whitespace friendly.
         */
    
        if ( !strncmp( CommandLine, "cd", 2 ) )
        {
          Result = chdir( CommandLine + 3 );
          if ( Result == -1 )
            perror( "shell" );
        }
        else if ( !strncmp( CommandLine, "exit", 4 ) )
        {
          StayAlive = 0;
        }
    
    
        /*
         *  Everything else we fake.
         */
    
        else
        {
          Result = system( CommandLine );
          if ( Result == -1 )
            perror( "shell" );
        }
      }
    
      /*
       *  If StayAlive is TRUE, we broke out due to error and
       *  errno should be returned.
       */
    
      return (StayAlive ? errno : 0 );
    }
    Jason Deckard

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Back To The Basics: Freeing An Array on the Heap?
    By Deo in forum C++ Programming
    Replies: 12
    Last Post: 04-07-2007, 04:42 AM
  2. HUGE fps jump
    By DavidP in forum Game Programming
    Replies: 23
    Last Post: 07-01-2004, 10:36 AM
  3. Pointer's
    By xlordt in forum C Programming
    Replies: 13
    Last Post: 10-14-2003, 02:15 PM
  4. Nero CD recording take long time
    By Eagle16 in forum A Brief History of Cprogramming.com
    Replies: 34
    Last Post: 11-15-2002, 05:49 PM
  5. How to encrypt a CD perfectly?
    By Yin in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 03-13-2002, 09:02 AM