1

Being quite new to writing shell. I am trying to get "cd" to go to home directory when I don't give any extra argument.

But when I call "cd" and the code tries to chdir(getenv("HOME")), it shows an error message "No such file or directory".

/*
  Builtin function implementations.
*/
int cd(char **args){
  if (args[1] == NULL){
    printf("%s\n", getenv("HOME"));
    if (chdir(getenv("HOME")) != 0) {
      perror("dsh");
    }
  } else if (chdir(args[1]) != 0){
    perror("dsh");
  }
  return 1;

}

getenv("HOME") does give correct directory, i.e. "/Users/oasisweng"

I guess I have done something incorrectly. Where should I fix? If possible, please tell me why.

I have read the chdir man here but if I manually enter cd /Users/oasisweng, then it will work.

Thank you!!

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
donkey
  • 4,285
  • 7
  • 42
  • 68
  • 5
    There's nothing wrong with that code. Consider posting an [MCVE](http://stackoverflow.com/help/mcve). – user3386109 Nov 02 '15 at 19:26
  • Does your code have a `chroot` call somewhere? – John Gordon Nov 02 '15 at 19:41
  • 2
    Are you sure that the result of `(args[1] == NULL)` is true? Try adding some `printf` calls, or run the program under a debugger, so you be sure it's doing what you think it's doing. Or temporarilyi coment out the `if` so it executes the code unconditionally. `chdir(getenv("HOME"))` should work, but `chdir(args[1])` may or may not. (My best guess is that `args[1]` is not a null pointer, but points to an empty string.) – Keith Thompson Nov 02 '15 at 20:02
  • 1
    BTW -- the `shell` tag is for code written **in** shell command language. If you had a question that was very, very specific to implementing a shell, perhaps that would be a good reason to use the tag from that end as well -- but such isn't the case here; you could reasonably have this question implementing many other kinds of programs as well. – Charles Duffy Nov 02 '15 at 21:30
  • Have you tried using `strace` or `sysdig` to look at the actual syscalls invoked (thus, at exactly what argument `chdir()` is passed)? You could get the same information tracing through execution with a debugger like gdb as well. – Charles Duffy Nov 02 '15 at 21:31

1 Answers1

0

Thank you for all of your help, I tried to follow the MCVE guideline when figuring out the answer. Because one has marked my question, I feel I should share my answer.

I found that the problem was how I initially set $HOME.

So basically, my shell read $HOME and $PATH variables in a file profile. It looks like this:

PATH=/bin:/usr/bin:/usr/local/bin\n
HOME=/Users/oasisweng\n

I split each line by = sign and setenv will save the value on the right to the name on the left.

The problem is that setenv function will also save \n as part of the $HOME when called!

cd(getenv("HOME")) is actually cd("/Users/oasisweng\n") with a newline character in the end. It fails since it should be cd("/Users/oasisweng").

My solution is to remove newline character for each value on the right side before setenv:

int remove_newline(char* str){
  char* rst = strchr(str,'\n');
  if (rst != NULL){
    *rst = '\0';
    //found and changed
    return 0;
  } else{
    //not found
    return 1;
  }
}

Boom! It is up and running.

This lesson is very trivial, but yet I think it is still a helpful reminder.

donkey
  • 4,285
  • 7
  • 42
  • 68
  • 1
    Um... So, how did you end up with these extra `\n` in your `profile` file? How did you manage to make them "visible" to `getenv`? If your lines in `profile` end with normal system-specific EOL character, it will not become part of variable value and will not be visible to `getenv`. It appears that your solution actually cures the symptoms of the real problem, not the problem itself. – AnT stands with Russia Nov 02 '15 at 23:22
  • So in my case, `profile` is edited in sublime text. I hit enter button for every new line. How do I make my enter button to enter system-specific EOL character? – donkey Nov 03 '15 at 10:52
  • I guess what I mean is that i did not enter every line with `shift+enter` as I did not do with `.bash_profile` for example. Is this necessary? – donkey Nov 03 '15 at 10:57