在C中将文件路径解析为可执行文件
Resolving filepath to executable in C
我目前的任务是用 C 语言编写原语 shell,但在实现 shell 功能时遇到了困难,该功能构建了给定请求程序的路径。例如将 wc
的用户输入转换为 /usr/bin/wc
。
Getenv() 可以很好地获取 $PATH 的值。使用我的导师提供的代码,我还将此值解析为单个 'tokens,',其中定义了一个标记:typedef char *tok_t
我的问题是如何修复以下函数的实现,如果找到,它寻求 return 给定文件名的绝对路径,否则 NULL
。
这里的主要问题是连接 tok_t
和 char*
以生成完整路径名。
char *resolve_path(char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
//fprint_tok(stdout, path_list);
char *path;
for (int i = 0; path_list[i]; i++) {
path = (char*) malloc(PATH_MAX);
strcat(path, *path_list[i]);
strcat(path, filename);
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
free(path);
}
return NULL;
}
我应该为 malloc() 和 strcat() 而烦恼,还是有更好的实现方法?目前正在获取有关使用 strcat() 的类型兼容性的段错误和警告。
您确实需要使用 malloc()
,因为您要从函数返回结果路径(指向在此函数中创建的自动数组的指针在函数 returns 之后将无效)。您确实需要使用 strcat()
或类似的方法来生成一个连续的 char *
以传递给 file_exists()
.
但是您的代码存在一些问题:
- 不要将
void *
显式转换为 C 中的其他类型 - 充其量是不必要的 (I'm talking about casting the return value of your allocation, in this case)。
- 检查
malloc()
是否失败。
- 您不需要在循环内调用
malloc()
和 free()
- 在循环外(每个)一次就足够了。
- 如果
tok_t
是 char *
,那么 path_list
是 char **
,因此当您将 path_list[i]
传递给 [=24] 时,无需取消引用 path_list[i]
=]/strncat()
,因为当他们期望字符串时,那只会是 char
。这可能是你的陈述 "Currently getting segfaults and warnings about the type compatibility in use of strcat()."
- 您需要在第一次调用
strcat()
之前将 path
的第一个字符设置为 NULL
,或者更好的是,使用 strncpy()
,在这种情况下您将完成后想将 path
的最后一个字符设置为 NULL。
- 将
strncat()
与 PATH_MAX - strlen(path)
一起使用,否则可能会溢出 path
。
这是一个例子:
char *resolve_path(const char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
char *path = malloc(PATH_MAX+1); // See, no cast, and the +1 is for the NULL
if (!path) {
return NULL; // Check for failure
}
// strncpy/strncat won't null-terminate path if we run out of space
path[PATH_MAX] = NULL;
for (int i = 0; path_list[i]; i++) {
// this could be done more efficiently with memcpy/hand-coding/etc
strncpy(path, path_list[i], PATH_MAX); // don't dereference it
strncat(path, filename, PATH_MAX - strlen(path));
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
}
free(path);
return NULL;
}
我正在阐述 因为按原样使用该代码仍然会导致分段错误。
因为 tok_t
只是 char*
的 typedef,它有点混淆你的代码。 get_toks()
是(没有 typedef 的)在技术上只是返回一个 char**
.
这意味着这一行:
strncpy(path, *path_list[i], PATH_MAX);
其实应该是
strncpy(path, path_list[i], PATH_MAX);
因为您不应该取消引用 path_list[i]
。如果这样做,当它需要 char*
时,您将 char
传递给 strncpy
。这就是您收到该警告和段错误的原因。
因此,无论其价值如何,这里是我对您的代码的更正:
char *resolve_path(const char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
char *path = malloc(PATH_MAX+1);
if (path == NULL) {
return NULL; // malloc failed
}
path[PATH_MAX] = '[=12=]'; // null terminate path
for (int i = 0; path_list[i]; i++) {
size_t len = strlen(path_list[i]); // get the length of this path
strncpy(path, path_list[i], PATH_MAX); // copy path_list to path
path[len] = '/'; // add seperator
strncat(path, filename, PATH_MAX - len - 1); // -1 because of separator
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
}
free(path);
return NULL;
}
我目前的任务是用 C 语言编写原语 shell,但在实现 shell 功能时遇到了困难,该功能构建了给定请求程序的路径。例如将 wc
的用户输入转换为 /usr/bin/wc
。
Getenv() 可以很好地获取 $PATH 的值。使用我的导师提供的代码,我还将此值解析为单个 'tokens,',其中定义了一个标记:typedef char *tok_t
我的问题是如何修复以下函数的实现,如果找到,它寻求 return 给定文件名的绝对路径,否则 NULL
。
这里的主要问题是连接 tok_t
和 char*
以生成完整路径名。
char *resolve_path(char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
//fprint_tok(stdout, path_list);
char *path;
for (int i = 0; path_list[i]; i++) {
path = (char*) malloc(PATH_MAX);
strcat(path, *path_list[i]);
strcat(path, filename);
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
free(path);
}
return NULL;
}
我应该为 malloc() 和 strcat() 而烦恼,还是有更好的实现方法?目前正在获取有关使用 strcat() 的类型兼容性的段错误和警告。
您确实需要使用 malloc()
,因为您要从函数返回结果路径(指向在此函数中创建的自动数组的指针在函数 returns 之后将无效)。您确实需要使用 strcat()
或类似的方法来生成一个连续的 char *
以传递给 file_exists()
.
但是您的代码存在一些问题:
- 不要将
void *
显式转换为 C 中的其他类型 - 充其量是不必要的 (I'm talking about casting the return value of your allocation, in this case)。 - 检查
malloc()
是否失败。 - 您不需要在循环内调用
malloc()
和free()
- 在循环外(每个)一次就足够了。 - 如果
tok_t
是char *
,那么path_list
是char **
,因此当您将path_list[i]
传递给 [=24] 时,无需取消引用path_list[i]
=]/strncat()
,因为当他们期望字符串时,那只会是char
。这可能是你的陈述 "Currently getting segfaults and warnings about the type compatibility in use of strcat()." - 您需要在第一次调用
strcat()
之前将path
的第一个字符设置为NULL
,或者更好的是,使用strncpy()
,在这种情况下您将完成后想将path
的最后一个字符设置为 NULL。 - 将
strncat()
与PATH_MAX - strlen(path)
一起使用,否则可能会溢出path
。
这是一个例子:
char *resolve_path(const char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
char *path = malloc(PATH_MAX+1); // See, no cast, and the +1 is for the NULL
if (!path) {
return NULL; // Check for failure
}
// strncpy/strncat won't null-terminate path if we run out of space
path[PATH_MAX] = NULL;
for (int i = 0; path_list[i]; i++) {
// this could be done more efficiently with memcpy/hand-coding/etc
strncpy(path, path_list[i], PATH_MAX); // don't dereference it
strncat(path, filename, PATH_MAX - strlen(path));
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
}
free(path);
return NULL;
}
我正在阐述
因为 tok_t
只是 char*
的 typedef,它有点混淆你的代码。 get_toks()
是(没有 typedef 的)在技术上只是返回一个 char**
.
这意味着这一行:
strncpy(path, *path_list[i], PATH_MAX);
其实应该是
strncpy(path, path_list[i], PATH_MAX);
因为您不应该取消引用 path_list[i]
。如果这样做,当它需要 char*
时,您将 char
传递给 strncpy
。这就是您收到该警告和段错误的原因。
因此,无论其价值如何,这里是我对您的代码的更正:
char *resolve_path(const char *filename) {
printf("trying to resolve path...\n");
char *path_var = getenv("PATH");
tok_t *path_list = get_toks(path_var);
char *path = malloc(PATH_MAX+1);
if (path == NULL) {
return NULL; // malloc failed
}
path[PATH_MAX] = '[=12=]'; // null terminate path
for (int i = 0; path_list[i]; i++) {
size_t len = strlen(path_list[i]); // get the length of this path
strncpy(path, path_list[i], PATH_MAX); // copy path_list to path
path[len] = '/'; // add seperator
strncat(path, filename, PATH_MAX - len - 1); // -1 because of separator
printf("Trying... %s\n", path);
if (file_exists(path)) {
return path;
}
}
free(path);
return NULL;
}