So I am studying system calls in c and I am doing this exercise that I have to make a simple program that search for a file in the PATH
(kinda similar to which
in Linux) and this is what I have done:
int main(int ac, char **av)
{
int i = 1;
struct stat buf;
char *_path, *token, *temp;
if (ac < 2)
{
printf("Usage: %s path_to_file ...\n", av[0]);
exit(-1);
}
while (i < ac)
{
if (stat(av[i], &buf) == 0)
{
printf("%s\n", av[i]);
}
else
{
_path = getenv("PATH");
token = strtok(_path, ":");
while (token != NULL)
{
temp = token;
strcat(temp, "/");
strcat(temp, av[i]);
if(stat(temp, &buf) == 0)
{
printf("%s\n", temp);
break;
}
token = strtok(NULL, ":");
}
printf("%s: no %s in (\"%s\")\n", av[0], av[i], _path);
}
i ;
}
return (0);
}
The following is my problem:
$ ./_which ls
Segmentation fault (core dumped)
If I add a printf as follows:
while (token != NULL)
{
temp = token;
strcat(temp, "/");
strcat(temp, av[i]);
printf("%s\n", temp);
if(stat(temp, &buf) == 0)
{
printf("%s\n", temp);
break;
}
token = strtok(NULL, ":");
}
Then I can see that strtok is never returning NULL
and is not even returning the correct string after.
$ ./_which ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
Segmentation fault (core dumped)
I have double-checked the how to use strtok but I couldn't find my problem.
CodePudding user response:
strtok modifies the 1st parameter, for every call it is called a static pointer is moved inside to point to another part of the parameter that was passed.
So when you do like this
temp = token;
it sets temp to point to a substring in the array that was passed and next time it is called with NULL as first parameter, temp will point to the next substring in the array, you cannot use what comes back from strtok other than as a source to copy from.
so first create a buffer large enough to hold the whole path.
char path[MAX_PATH 1]={'\0'};
then strcat to that buffer.
strcpy(path, token);
strcat(path, "/");
strcat(path, av[i]);
Another problem with you code is changing what comes back from getenv(). Copy that first to a buffer and then call strtok on that
e.g.
char* env = getenv("PATH");
char* fullEnv = malloc(strlen(env) 1);
strcpy(fullEnv,env);
// alternatively use
// char* fullEnv=strdup(getenv("PATH"));
token = strtok(fullEnv, ":");
...
free(fullEnv);
a final comment, don't declare variables with leading underscore, it is mainly used for internal compiler variables and could cause you hard to find issues.