I am writing my own shell in C/Ubuntu for a project but I had some diffuculties when using chdir()
to implement cd
. chdir()
needs a path name but since the user will write (lets assume) cd Desktop
, Desktop
is not a path name so the program will fail.
Here is that part of my code:
child = fork();
if (child == 0) {
if (!strcmp(args[0], "ls")) {
execv("/bin/ls", args);
}
if (!strcmp(args[0] , "cd")) {
chdir(args[1]);
}
perror("Error");
exit(1); //Failure
} else {
do {
waitpid(child, &status, WUNTRACED);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
So I think the problem is that args[1]
gets things like "Desktop"
etc instead of the address so chdir
fails. I tested it in terminal, all other commands work except cd
. My question is that how can I make this chdir
work?In another words how can I give the path of args[1]
to chdir
?
Let me put it in this way. When I write cd Desktop
to terminal it works. When I write cd Desktop
to my own shell it tries to execute chdir("Desktop")
and it fails.
You use use exec
to run the ls
command, I suspect you fork()
the process before selecting which command to execute: chdir(args[1])
is executed in the child process, the child process changes its current directory and then exits. Each process has its own current directory. The parent (shell) process current directory in unaffected by the change in its child, it keeps its current directory.
Most command should be executed in the shell process without forking, only external commands should be executed after forking to a child process.
Here is a modified version of your code:
/* frist execute local commands in the shell process. */
if (!strcmp(args[0], "cd")) {
if (!args[1]) {
fprintf(stderr, "cd: missing argument\n");
} else
if (chdir(args[1])) {
perror("chdir");
}
} else
if (!strcmp(args[0], "exit")) {
int status = args[1] ? atoi(argv[1]) : 0;
exit(status);
} else {
/* otherwise, fork and attempt to execute an external command */
child = fork();
if (child == 0) {
if (!strcmp(args[0], "ls")) {
execv("/bin/ls", args);
}
/* if exec failed, the child process is still running */
perror("exec");
exit(1); //Failure
} else {
do {
waitpid(child, &status, WUNTRACED);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}