-2

I'm trying to implement the cd command in C. It should be this simple

printf("change directory to %s\n" , argv[2]);
chdir(argv[2]);

Why doesn't it work for me? The code is here in a complete program which does some other things as well. I could create a minimal example if we must.

    $ cc digenv.c
    developer@developer-VirtualBox:~/Desktop/kth/os/smallshell/oslab$ ./a.out cd test
    change directory to test
    developer@developer-VirtualBox:~/Desktop/kth/os/smallshell/oslab$ pwd
    /home/developer/Desktop/kth/os/smallshell/oslab
    developer@developer-VirtualBox:~/Desktop/kth/os/smallshell/oslab$ ls test
    developer@developer-VirtualBox:~/Desktop/kth/os/smallshell/oslab$

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
    const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
    pid_t pid;
    if ((pid = fork ()) == 0) {
        if (in != 0) {
            dup2 (in, 0);
            close (in);
        }
        if (out != 1) {
            dup2 (out, 1);
            close (out);
        }
        return execvp (cmd->argv [0], (char * const *)cmd->argv);
    }
    return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
    int i;
    int in, fd [2];
    in = 0;
    for (i = 0; i < n - 1; ++i) {
        pipe (fd);
        spawn_proc (in, fd [1], cmd + i);
        close (fd [1]);
        in = fd [0];
    }
    if (in != 0)
        dup2 (in, 0);
    return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
}

int main (int argc, char ** argv) {
    int i;
    if (argc == 1) { /* There were no arguments */
        const char *printenv[] = { "printenv", 0};
        const char *sort[] = { "sort", 0 };
        const char *less[] = { "less", 0 };
        struct command cmd [] = { {printenv}, {sort}, {less} };
        return fork_pipes (3, cmd);
    }
    if (argc > 1) { /* I'd like an argument */

        if (strncmp(argv[1], "cd", 2)) {
            char *tmp;
            int len = 1;
            for( i=1; i<argc; i++)
            {
                len += strlen(argv[i]) + 2;
            }
            tmp = (char*) malloc(len);
            tmp[0] = '\0';
            int pos = 0;
            for( i=1; i<argc; i++)
            {
                pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
            }
            const char *printenv[] = { "printenv", 0};
            const char *grep[] = { "grep", "-E", tmp, NULL};
            const char *sort[] = { "sort", 0 };
            const char *less[] = { "less", 0 };
            struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
            return fork_pipes (4, cmd);
            free(tmp);
        } else { /* change directory */
printf("change directory to %s\n" , argv[2]);
            chdir(argv[2]);
        }
    }
    exit(0);
}
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 4
    Yes, we must create a minimal example. – Fiddling Bits Apr 05 '15 at 22:06
  • 2
    Your program is a separate process from your shell; it cannot affect its current directory. – Oliver Charlesworth Apr 05 '15 at 22:08
  • 2
    Your chdir command changes the directory for it's own process. Then, when that process exits, you are back in the shell process, which has it's own, separate 'current directory'. The 'cd' command is actually implemented internally to the 'bash' process, and it uses `chdir()` to move the directory of the bash process internally. – JohnH Apr 05 '15 at 22:10
  • 1
    It's difficult to believe this is not a dup, but can't find one off-hand. – Martin James Apr 05 '15 at 23:50
  • Thank you for the comments. I learn from these comments. – Niklas Rosencrantz Apr 06 '15 at 02:42
  • @MartinJames: 'Tis astonishingly hard. I found [Unix commands implemented in C](http://stackoverflow.com/questions/9339472/unix-commands-implemented-in-c) which mentions `cd` not working and the code has the same problem as here, but the answers are about the I/O redirection part of the question, not the `chdir()` part. – Jonathan Leffler Apr 07 '15 at 04:34

1 Answers1

6

As per its documentation

The chdir() function only affects the working directory of the current process.

So you cannot change the directory of the parent process.

Diego
  • 1,789
  • 10
  • 19
  • _[…Completely tangential to this question…]_ Diego, you could have fixed your answer to the Mac OS X `sed` question you answered on 2015-04-06, instead of deleting it. It wasn't a bad answer, for all you slightly misinterpreted one bit of the manual that you quoted (but that's not hard to do — it is an unusual case). Please flag this comment for deletion when you've read it. – Jonathan Leffler Apr 07 '15 at 03:42