Im trying to write a basic shell that can interpret simple commands like date, ls in the language c.
I start by getting the PATH variable like this to later pass it on to the execv() function.
const char *name = "PATH";
char *value;
value = getenv(name)
and i print out the value and i get this:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
Note that i am using virutalbox to run Ubuntu. And this is the code that i am using to try a simple ls command. In the code below the variable line is the actual command that the user wrote, in our case it is "ls"
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) {
// Child process
if (execv(value, line) == -1) {
perror("lsh");
}
exit(EXIT_FAILURE);
}
else if (pid < 0) {
// Error forking
perror("lsh");
}
else {
// Parent process
do {
wpid = waitpid(pid, &status, WUNTRACED);
}
while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
And the result i get is this:
lsh: no such file or directory
any ideas?
The execv()
system call uses the name you specify in the first argument as the file name of the executable; it does not do a PATH-based search.
That means that if you specify "lsh"
as the first argument, there must be an executable file lsh
in the current directory.
If you want a PATH-based search, replace execv()
with execvp()
. Otherwise, specify the pathname — absolute or relative, but absolute is more normal — of the command in the first argument.
Note that if any of the exec*()
functions returns, it has failed. There's no need to test the return value; it will always be -1.
The contents of value
and line
need to be along the lines of:
char *value = "ls";
char *line[] = { "ls", "-l", 0 };
execvp(value, line);
or, more conventionally:
execvp(line[0], line);
If you are analyzing the PATH yourself, you'll need to have line[0]
pointing at the complete file name that you've created from PATH, and then you use execv()
instead of execvp()
.