这个问题是针对Linux的;解决方案不需要是便携式的。
我正在寻找一个库函数/系统调用,或者它的一些组合,它将为任意文件提供设备(例如:/dev/sdb1
)或挂载点(例如:/home
)。看起来f_fsid
结构的statfs
字段会起作用,但它不会在Linux上使用。
我可以使用shell轻松找到这些信息:
df "$filename" | awk 'NR==1 {next} {print $6; exit}'
但似乎没有exec
函数系列从运行的命令返回输出,我宁愿保持我的解决方案纯C。
答案 0 :(得分:1)
答案 1 :(得分:0)
我使用stat()
编写了一个纯C解决方案。对于那些可能在搜索中找到这个的人来说,这里有一个功能:
int getmntpt(char *path, char *mount_point) {
struct stat cur_stat;
struct stat last_stat;
char dir_name[PATH_MAX];
char *dirname_p = dir_name;
char cur_cwd[255];
char *cur_cwd_p = cur_cwd;
char saved_cwd[PATH_MAX];
if (getcwd(saved_cwd, PATH_MAX) == NULL) {
errno = EIO;
return ERROR;
}
if (lstat(path, &cur_stat) < 0) {
errno = EIO;
return ERROR;
}
if (S_ISDIR (cur_stat.st_mode)) {
last_stat = cur_stat;
if (chdir("..") < 0)
return ERROR;
if (getcwd(cur_cwd_p, 255) == NULL) {
errno = EIO;
return ERROR;
}
} else { /* path is a file */
size_t path_len, suffix_len, dir_len;
path_len = strlen(path);
suffix_len = strlen(strrchr(path, 47)); /* 47 = '/' */
dir_len = path_len - suffix_len;
dirname_p = strncpy(dirname_p, path, dir_len);
if (chdir(dirname_p) < 0)
return ERROR;
if (lstat(".", &last_stat) < 0)
return ERROR;
}
for (;;) {
if (lstat("..", &cur_stat) < 0)
return ERROR;
if (cur_stat.st_dev != last_stat.st_dev || cur_stat.st_ino == last_stat.st_ino)
break; /* this is the mount point */
if (chdir("..") < 0)
return ERROR;
last_stat = cur_stat;
}
if (getcwd(mount_point, PATH_MAX) == NULL)
return ERROR;
if (chdir(saved_cwd) < 0)
return ERROR;
return SUCCESS;
}
答案 2 :(得分:0)
这是我根据@DarrenKirby的答案编写的C解决方案,但它避免使用chdir
,并且更短。 [此外,它还处理了将挂载点本身作为参数传递的极端情况。
int getmntpt(char const *path, char *mount_point) {
char *test_path = malloc(PATH_MAX), *test_end;
struct stat cur_stat, prev_stat;
if (lstat(path, &prev_stat) < 0)
return ERROR;
test_end = stpcpy(test_path, path);
if (!S_ISDIR(prev_stat.st_mode)) {
test_end = strrchr(test_path, '/');
if (test_end == NULL)
test_end = stpcpy(test_path, ".");
else
*test_end = '\0';
}
for (;;) {
test_end = stpcpy(test_end, "/..");
if (lstat(test_path, &cur_stat) < 0)
return ERROR;
if (cur_stat.st_dev != prev_stat.st_dev || cur_stat.st_ino == prev_stat.st_ino) /* root */
break; /* this is the mount point */
prev_stat = cur_stat;
}
*(test_end - 3) = '\0';
if (realpath(test_path, mount_point) == NULL) {
free(test_path);
return -1;
}
return 0;
}