mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 02:49:02 -04:00
Resolve ZFS dataset mounts through mountinfo, including legacy mountpoints
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-arm32 (push) Waiting to run
Build / build-win (push) Waiting to run
Build / build-freebsd (push) Waiting to run
Build / build-musl (push) Waiting to run
CodeQL Advanced / Analyze (c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-arm32 (push) Waiting to run
Build / build-win (push) Waiting to run
Build / build-freebsd (push) Waiting to run
Build / build-musl (push) Waiting to run
CodeQL Advanced / Analyze (c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
This commit is contained in:
parent
1aa6d2b787
commit
afba275a0e
1 changed files with 110 additions and 24 deletions
|
|
@ -971,9 +971,83 @@ bail:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int extract_zfs_mount(const char* resolved, char* dataset, size_t dataset_size, char* mount_point, size_t mount_point_size)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(resolved, &st) != 0)
|
||||
return -1;
|
||||
|
||||
FILE* fd = fopen("/proc/self/mountinfo", "r");
|
||||
if (!fd)
|
||||
return -1;
|
||||
|
||||
size_t best_len = 0;
|
||||
while (1) {
|
||||
char buf[PATH_MAX * 2 + 64];
|
||||
char* id_map[8];
|
||||
unsigned id_mac;
|
||||
char* fs_map[8];
|
||||
unsigned fs_mac;
|
||||
unsigned mount_major;
|
||||
unsigned mount_minor;
|
||||
|
||||
char* s = fgets(buf, sizeof(buf), fd);
|
||||
if (s == 0)
|
||||
break;
|
||||
|
||||
/* find the separator position */
|
||||
char* separator = strstr(s, " - ");
|
||||
if (!separator)
|
||||
continue;
|
||||
|
||||
/* skip the separator */
|
||||
*separator = 0;
|
||||
separator += 3;
|
||||
|
||||
/* split the line */
|
||||
id_mac = strsplit(id_map, 8, s, " \t\r\n", 0, 1);
|
||||
fs_mac = strsplit(fs_map, 8, separator, " \t\r\n", 0, 1);
|
||||
|
||||
if (id_mac < 5 || fs_mac < 2)
|
||||
continue;
|
||||
|
||||
/* mount point must contain the directory */
|
||||
unescape_mount(id_map[4]);
|
||||
const char* mp = id_map[4];
|
||||
size_t mp_len = strlen(mp);
|
||||
if (strncmp(resolved, mp, mp_len) != 0)
|
||||
continue;
|
||||
if (mp_len > 1 && resolved[mp_len] != '/' && resolved[mp_len] != 0)
|
||||
continue;
|
||||
|
||||
/* match the device backing the path, not a hidden parent mount */
|
||||
if (strcmp(fs_map[0], "zfs") != 0
|
||||
|| sscanf(id_map[2], "%u:%u", &mount_major, &mount_minor) != 2
|
||||
|| mount_major != major(st.st_dev) || mount_minor != minor(st.st_dev))
|
||||
continue;
|
||||
|
||||
/* use the visible mount, including a legacy mount under a parent dataset */
|
||||
if (mp_len > best_len) {
|
||||
best_len = mp_len;
|
||||
unescape_mount(fs_map[1]);
|
||||
pathcpy(dataset, dataset_size, fs_map[1]);
|
||||
pathcpy(mount_point, mount_point_size, mp);
|
||||
}
|
||||
}
|
||||
|
||||
int error = ferror(fd);
|
||||
if (fclose(fd) != 0 || error)
|
||||
return -1;
|
||||
|
||||
return best_len == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static int extract_zfs(const char* dir, char* dataset, size_t dataset_size, char* uuid, size_t uuid_size, char* mount_point, size_t mount_point_size)
|
||||
{
|
||||
char resolved[PATH_MAX];
|
||||
char mounted_dataset[PATH_MAX];
|
||||
char mounted_point[PATH_MAX];
|
||||
|
||||
const char* zfs = find_zfs();
|
||||
if (!zfs) {
|
||||
|
|
@ -988,13 +1062,16 @@ static int extract_zfs(const char* dir, char* dataset, size_t dataset_size, char
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (extract_zfs_mount(resolved, mounted_dataset, sizeof(mounted_dataset), mounted_point, sizeof(mounted_point)) != 0)
|
||||
return -1;
|
||||
|
||||
/* list all ZFS filesystems in one shot */
|
||||
const char* argv[] = {
|
||||
zfs,
|
||||
"list",
|
||||
"-H",
|
||||
"-o",
|
||||
"name,guid,mountpoint",
|
||||
"name,guid",
|
||||
"-t",
|
||||
"filesystem",
|
||||
0
|
||||
|
|
@ -1007,10 +1084,10 @@ static int extract_zfs(const char* dir, char* dataset, size_t dataset_size, char
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
size_t best_len = 0;
|
||||
int found = 0;
|
||||
while (1) {
|
||||
char buf[PATH_MAX * 2 + 64];
|
||||
char* map[3];
|
||||
char* map[2];
|
||||
unsigned mac;
|
||||
|
||||
char* s = os_fgets(buf, sizeof(buf), fp);
|
||||
|
|
@ -1018,33 +1095,36 @@ static int extract_zfs(const char* dir, char* dataset, size_t dataset_size, char
|
|||
break;
|
||||
|
||||
/* split the line */
|
||||
mac = strsplit(map, 3, s, "\t\r\n", 0, 1);
|
||||
mac = strsplit(map, 2, s, "\t\r\n", 0, 1);
|
||||
|
||||
if (mac < 3)
|
||||
if (mac < 2 || strcmp(map[0], mounted_dataset) != 0)
|
||||
continue;
|
||||
|
||||
const char* mp = map[2];
|
||||
size_t mp_len = strlen(mp);
|
||||
if (strncmp(resolved, mp, mp_len) != 0)
|
||||
continue;
|
||||
if (mp_len > 1 && resolved[mp_len] != '/' && resolved[mp_len] != 0)
|
||||
continue;
|
||||
|
||||
/* keep the longest (innermost) match */
|
||||
if (mp_len > best_len) {
|
||||
best_len = mp_len;
|
||||
if (dataset)
|
||||
pathcpy(dataset, dataset_size, map[0]);
|
||||
if (uuid)
|
||||
pathcpy(uuid, uuid_size, map[1]);
|
||||
if (mount_point)
|
||||
pathcpy(mount_point, mount_point_size, map[2]);
|
||||
}
|
||||
found = 1;
|
||||
if (dataset)
|
||||
pathcpy(dataset, dataset_size, map[0]);
|
||||
if (uuid)
|
||||
pathcpy(uuid, uuid_size, map[1]);
|
||||
if (mount_point)
|
||||
pathcpy(mount_point, mount_point_size, mounted_point);
|
||||
}
|
||||
|
||||
os_pclose(fp);
|
||||
/* incomplete output cannot confirm the mounted dataset's GUID */
|
||||
int ret = os_pclose(fp);
|
||||
if (ret < 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_error(errno, "Failed to close ZFS dataset list for '%s'. %s.\n", dir, strerror(errno));
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
if (ret != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_error(ESOFT, "Failed to list ZFS datasets for '%s' (status %d).\n", dir, ret);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (best_len == 0) {
|
||||
if (!found) {
|
||||
/* LCOV_EXCL_START */
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
|
@ -1855,6 +1935,12 @@ static int devuuid_bcachefs(uint64_t device, const char* dir, char* uuid, size_t
|
|||
#if HAVE_LINUX_DEVICE
|
||||
int devuuid_zfs(uint64_t device, const char* dir, char* uuid, size_t uuid_size)
|
||||
{
|
||||
struct statfs sfs;
|
||||
|
||||
/* only report ZFS lookup failures after identifying the filesystem */
|
||||
if (statfs(dir, &sfs) != 0 || statfs_type(&sfs) != ZFS_SUPER_MAGIC)
|
||||
return -1;
|
||||
|
||||
if (extract_zfs(dir, 0, 0, uuid, uuid_size, 0, 0) != 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue