More coverage support

This commit is contained in:
Andrea Mazzoleni 2026-04-29 14:51:40 +02:00
parent 8a727975ab
commit c724b47189
3 changed files with 178 additions and 56 deletions

View file

@ -936,6 +936,7 @@ void signal_init(void)
#define OPERATION_SMART 17
#define OPERATION_PROBE 18
#define OPERATION_LOCATE 19
#define OPERATION_SPINDOWNIFUP 20
int snapraid_main(int argc, char* argv[])
{
@ -1497,6 +1498,8 @@ int snapraid_main(int argc, char* argv[])
operation = OPERATION_SPINUP;
} else if (strcmp(argv[optind], "down") == 0) {
operation = OPERATION_SPINDOWN;
} else if (strcmp(argv[optind], "test-downifup") == 0) {
operation = OPERATION_SPINDOWNIFUP;
} else if (strcmp(argv[optind], "devices") == 0) {
operation = OPERATION_DEVICES;
} else if (strcmp(argv[optind], "smart") == 0) {
@ -1533,6 +1536,7 @@ int snapraid_main(int argc, char* argv[])
case OPERATION_DEVICES :
case OPERATION_SPINUP :
case OPERATION_SPINDOWN :
case OPERATION_SPINDOWNIFUP :
break;
default :
if (opt.force_device) {
@ -1626,6 +1630,7 @@ int snapraid_main(int argc, char* argv[])
/* fallthrough */
case OPERATION_SPINUP :
case OPERATION_SPINDOWN :
case OPERATION_SPINDOWNIFUP :
if (!tommy_list_empty(&filterlist_file)) {
/* LCOV_EXCL_START */
log_fatal(EUSER, "You cannot use -f, --filter with the '%s' command\n", command);
@ -1713,6 +1718,7 @@ int snapraid_main(int argc, char* argv[])
case OPERATION_TOUCH :
case OPERATION_SPINUP :
case OPERATION_SPINDOWN :
case OPERATION_SPINDOWNIFUP :
case OPERATION_DEVICES :
case OPERATION_SMART :
case OPERATION_PROBE :
@ -1979,6 +1985,12 @@ int snapraid_main(int argc, char* argv[])
#if HAVE_CHECKER
if (ret < 0)
ret = 0; /* ignore errors in test environment */
#endif
} else if (operation == OPERATION_SPINDOWNIFUP) {
ret = state_device(&state, DEVICE_DOWNIFUP, &filterlist_disk);
#if HAVE_TEST_RUN
if (ret < 0)
ret = 0; /* ignore errors in test environment */
#endif
} else if (operation == OPERATION_DEVICES) {
ret = state_device(&state, DEVICE_LIST, 0);

View file

@ -199,12 +199,18 @@ static int sysattr_vpd_pg80(const char* path, char* dst, size_t dst_size)
int ret = sysread(path, (char*)buf, sizeof(buf));
/* need at least the header */
if (ret < 4)
if (ret < 4) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* validate page code */
if (buf[1] != 0x80)
if (buf[1] != 0x80) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* clamp to what was actually read */
size_t page_len = buf[3];
@ -213,20 +219,29 @@ static int sysattr_vpd_pg80(const char* path, char* dst, size_t dst_size)
page_len = available;
/* if empty */
if (page_len == 0)
if (page_len == 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* if too bit to store the 0 termination */
if (4 + page_len + 1 > sizeof(buf))
if (4 + page_len + 1 > sizeof(buf)) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
char* attr = (char*)buf + 4;
attr[page_len] = 0;
strtrim(attr);
/* if empty */
if (!*attr)
if (!*attr) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
pathcpy(dst, dst_size, attr);
return 0;
@ -283,12 +298,18 @@ static int sysattr_vpd_pg83(const char* path, char* dst, size_t dst_size)
unsigned char buf[4096];
int ret = sysread(path, (char*)buf, sizeof(buf));
if (ret < 4)
if (ret < 4) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* validate page code */
if (buf[1] != 0x83)
if (buf[1] != 0x83) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
size_t page_len = ((size_t)buf[2] << 8) | buf[3];
@ -298,8 +319,11 @@ static int sysattr_vpd_pg83(const char* path, char* dst, size_t dst_size)
page_len = available;
/* if empty */
if (page_len == 0)
if (page_len == 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/*
* Walk every Designation Descriptor looking for the first NAA descriptor
@ -438,29 +462,40 @@ static int devdereference(uint64_t device, const char* dir, tommy_list* devlist)
struct statfs sfs;
int fd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (fd < 0)
if (fd < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
if (fstatfs(fd, &sfs) != 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
if (sfs.f_type != BTRFS_SUPER_MAGIC) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
struct btrfs_ioctl_fs_info_args fs_info;
memset(&fs_info, 0, sizeof(fs_info));
if (ioctl(fd, BTRFS_IOC_FS_INFO, &fs_info) < 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
if (fs_info.max_id == 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
for (__u64 i = 1; i <= fs_info.max_id; ++i) {
@ -469,15 +504,19 @@ static int devdereference(uint64_t device, const char* dir, tommy_list* devlist)
dev_info.devid = i;
if (ioctl(fd, BTRFS_IOC_DEV_INFO, &dev_info) != 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
/* get major:minor, use stat on the path returned */
struct stat st;
if (stat((char*)dev_info.path, &st) != 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
struct dev_struct* dev = malloc_nofail(sizeof(struct dev_struct));
@ -662,16 +701,20 @@ static int devuuid_dev(uint64_t device, char* uuid, size_t uuid_size)
/* scan the UUID directory searching for the device */
d = opendir("/dev/disk/by-uuid");
if (!d) {
/* LCOV_EXCL_START */
log_tag("uuid:by-uuid:%u:%u: opendir(/dev/disk/by-uuid) failed, %s\n", major(device), minor(device), strerror(errno));
/* directory missing?, likely we are not in Linux */
return -1;
/* LCOV_EXCL_STOP */
}
int dir_fd = dirfd(d);
if (dir_fd == -1) {
/* LCOV_EXCL_START */
log_tag("uuid:by-uuid:%u:%u: dirfd(/dev/disk/by-uuid) failed, %s\n", major(device), minor(device), strerror(errno));
closedir(d);
return -1;
/* LCOV_EXCL_STOP */
}
while ((dd = readdir(d)) != 0) {
@ -681,9 +724,11 @@ static int devuuid_dev(uint64_t device, char* uuid, size_t uuid_size)
ret = fstatat(dir_fd, dd->d_name, &st, 0);
if (ret != 0) {
/* LCOV_EXCL_START */
log_tag("uuid:by-uuid:%u:%u: fstatat(%s) failed, %s\n", major(device), minor(device), dd->d_name, strerror(errno));
/* generic error, ignore and continue the search */
continue;
/* LCOV_EXCL_STOP */
}
/* if it matches, we have the uuid */
@ -695,9 +740,11 @@ static int devuuid_dev(uint64_t device, char* uuid, size_t uuid_size)
pathprint(path, sizeof(path), "/dev/disk/by-uuid/%s", dd->d_name);
ret = readlink(path, buf, sizeof(buf));
if (ret < 0 || ret >= PATH_MAX) {
/* LCOV_EXCL_START */
log_tag("uuid:by-uuid:%u:%u: readlink(/dev/disk/by-uuid/%s) failed, %s\n", major(device), minor(device), dd->d_name, strerror(errno));
/* generic error, ignore and continue the search */
continue;
/* LCOV_EXCL_STOP */
}
buf[ret] = 0;
@ -735,17 +782,21 @@ static int devuuid_blkid(uint64_t device, char* uuid, size_t uuid_size)
devname = blkid_devno_to_devname(device);
if (!devname) {
/* LCOV_EXCL_START */
log_tag("uuid:blkid:%u:%u: blkid_devno_to_devname() failed, %s\n", major(device), minor(device), strerror(errno));
/* device mapping failed */
return -1;
/* LCOV_EXCL_STOP */
}
uuidname = blkid_get_tag_value(cache, "UUID", devname);
if (!uuidname) {
/* LCOV_EXCL_START */
log_tag("uuid:blkid:%u:%u: blkid_get_tag_value(UUID,%s) failed, %s\n", major(device), minor(device), devname, strerror(errno));
/* uuid mapping failed */
free(devname);
return -1;
/* LCOV_EXCL_STOP */
}
pathcpy(uuid, uuid_size, uuidname);
@ -772,17 +823,21 @@ static int devuuid_label(uint64_t device, char* label, size_t label_size)
devname = blkid_devno_to_devname(device);
if (!devname) {
/* LCOV_EXCL_START */
log_tag("label:blkid:%u:%u: blkid_devno_to_devname() failed, %s\n", major(device), minor(device), strerror(errno));
/* device mapping failed */
return -1;
/* LCOV_EXCL_STOP */
}
labelname = blkid_get_tag_value(cache, "LABEL", devname);
if (!labelname) {
/* LCOV_EXCL_START */
log_tag("label:blkid:%u:%u: blkid_get_tag_value(LABEL,%s) failed, %s\n", major(device), minor(device), devname, strerror(errno));
free(devname);
/* label mapping failed */
return -1;
/* LCOV_EXCL_STOP */
}
pathcpy(label, label_size, labelname);
@ -884,12 +939,17 @@ static int devuuid_btrfs(uint64_t device, const char* dir, char* uuid, size_t uu
struct statfs sfs;
int fd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (fd < 0)
if (fd < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP*/
}
if (fstatfs(fd, &sfs) != 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
if (sfs.f_type != BTRFS_SUPER_MAGIC) {
@ -900,8 +960,10 @@ static int devuuid_btrfs(uint64_t device, const char* dir, char* uuid, size_t uu
struct btrfs_ioctl_fs_info_args info;
memset(&info, 0, sizeof(info));
if (ioctl(fd, BTRFS_IOC_FS_INFO, &info) < 0) {
/* LCOV_EXCL_START */
close(fd);
return -1;
/* LCOV_EXCL_STOP */
}
snprintf(uuid, uuid_size,
@ -975,7 +1037,9 @@ int filephy(const char* path, uint64_t size, uint64_t* physical)
f = open(path, O_RDONLY);
if (f == -1) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/*
@ -1276,7 +1340,9 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
char* slash;
if (errno != ENOENT) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/*
@ -1284,19 +1350,27 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har
* and we check for the containing dir
*/
if (strlen(path) + 1 > sizeof(dir)) {
/* LCOV_EXCL_START */
errno = ENAMETOOLONG;
return -1;
/* LCOV_EXCL_STOP */
}
strcpy(dir, path);
slash = strrchr(dir, '/');
if (!slash)
if (!slash) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
*slash = 0;
if (statfs(dir, &st) != 0)
if (statfs(dir, &st) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
#endif
@ -1401,8 +1475,10 @@ int fssnapshot(const char* path, char* root, size_t root_size)
pathcpy(current_path, sizeof(current_path), path);
if (statfs(current_path, &sfs) != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error stating filesystem '%s'. %s.\n", current_path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
/* only btrfs */
@ -1412,8 +1488,10 @@ int fssnapshot(const char* path, char* root, size_t root_size)
/* walk up the directory tree to find the subvolume root (Inode 256) */
while (1) {
if (stat(current_path, &st) != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error stating '%s'. %s.\n", current_path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
/* btrfs reserved inode 256 for subvolume roots */
@ -1427,8 +1505,10 @@ int fssnapshot(const char* path, char* root, size_t root_size)
pathup(current_path);
if (current_path[0] == 0) {
/* LCOV_EXCL_START */
log_error(ENOENT, "No subvolume root found for '%s'. %s.\n", path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
}
#else
@ -1450,13 +1530,17 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
/* open the source subvolume to get a file descriptor */
fd_source = open(source, O_RDONLY | O_DIRECTORY);
if (fd_source < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
fd_dest_parent = open(parent_dir, O_RDONLY | O_DIRECTORY);
if (fd_dest_parent < 0) {
/* LCOV_EXCL_START */
close(fd_source);
return -1;
/* LCOV_EXCL_STOP */
}
memset(&args, 0, sizeof(args));
@ -1466,11 +1550,12 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
/* issue the snapshot command to the PARENT directory of the destination */
ret = ioctl(fd_dest_parent, BTRFS_IOC_SNAP_CREATE_V2, &args);
if (ret < 0) {
/* LCOV_EXCL_START */
close(fd_source);
close(fd_dest_parent);
return -1;
/* LCOV_EXCL_STOP */
}
close(fd_source);
@ -1494,7 +1579,9 @@ int fssnapshot_delete(const char* parent_dir, const char* name)
fd_parent = open(parent_dir, O_RDONLY | O_DIRECTORY);
if (fd_parent < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
memset(&args, 0, sizeof(args));
@ -1503,8 +1590,10 @@ int fssnapshot_delete(const char* parent_dir, const char* name)
ret = ioctl(fd_parent, BTRFS_IOC_SNAP_DESTROY, &args);
if (ret < 0 && errno != ENOENT) {
/* LCOV_EXCL_START */
close(fd_parent);
return -1;
/* LCOV_EXCL_STOP */
}
close(fd_parent);
@ -1529,8 +1618,11 @@ int fssnapshot_rename(const char* parent_dir, const char* old_name, const char*
pathcatc(new_path, sizeof(new_path), '/');
pathcat(new_path, sizeof(new_path), new_name);
if (rename(old_path, new_path) < 0)
if (rename(old_path, new_path) < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
#else
@ -1541,38 +1633,6 @@ int fssnapshot_rename(const char* parent_dir, const char* old_name, const char*
#endif
}
int fssnapshot_clone(const char* source, const char* dest)
{
#if HAVE_LINUX_DEVICE
int fs, fd;
fs = open(source, O_RDONLY);
if (fs < 0)
return -1;
fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
close(fs);
return 1;
}
/* perform the reflink copy */
if (ioctl(fd, FICLONE, fs) < 0) {
close(fd);
close(fs);
return -1;
}
close(fs);
close(fd);
return 0;
#else
(void)source;
(void)dest;
return -1;
#endif
}
uint64_t os_tick(void)
{
#if HAVE_MACH_ABSOLUTE_TIME
@ -1588,7 +1648,9 @@ uint64_t os_tick(void)
#else
if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
#endif
/* LCOV_EXCL_START */
return 0;
/* LCOV_EXCL_STOP */
}
return tv.tv_sec * 1000000000ULL + tv.tv_nsec;
@ -1598,7 +1660,9 @@ uint64_t os_tick(void)
/* microsecond precision with gettimeofday() */
if (gettimeofday(&tv, 0) != 0) {
/* LCOV_EXCL_START */
return 0;
/* LCOV_EXCL_STOP */
}
return tv.tv_sec * 1000000ULL + tv.tv_usec;
@ -1609,8 +1673,11 @@ uint64_t os_tick_ms(void)
{
struct timeval tv;
if (gettimeofday(&tv, 0) != 0)
if (gettimeofday(&tv, 0) != 0) {
/* LCOV_EXCL_START */
return 0;
/* LCOV_EXCL_STOP */
}
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
}
@ -1621,17 +1688,25 @@ int randomize(void* ptr, size_t size)
ssize_t ret;
f = open("/dev/urandom", O_RDONLY);
if (f == -1)
if (f == -1) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
ret = read(f, ptr, size);
if (ret < 0 || (size_t)ret != size) {
/* LCOV_EXCL_START */
close(f);
return -1;
/* LCOV_EXCL_STOP */
}
if (close(f) != 0)
if (close(f) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
@ -1851,8 +1926,11 @@ static int devstat(dev_t device, uint64_t* count)
*i++ = 0; /* put a terminator */
v = strtoull(n, &e, 10);
if (*e != 0)
if (*e != 0) {
/* LCOV_EXCL_START */
break;
/* LCOV_EXCL_STOP */
}
/* sum reads and writes completed */
if (token == 1 || token == 5) {
@ -2758,8 +2836,11 @@ int ambient_temperature(void)
int lowest_temp = 0;
dir = opendir("/sys/class/hwmon");
if (!dir)
if (!dir) {
/* LCOV_EXCL_START */
return 0;
/* LCOV_EXCL_STOP */
}
/* iterate through hwmon devices */
while ((entry = readdir(dir)) != NULL) {
@ -2774,8 +2855,11 @@ int ambient_temperature(void)
/* iterate through temp*_input files */
hwmon_dir = opendir(path);
if (!hwmon_dir)
if (!hwmon_dir) {
/* LCOV_EXCL_START */
continue;
/* LCOV_EXCL_STOP */
}
while ((hwmon_entry = readdir(hwmon_dir)) != NULL) {
char hwmon_name[PATH_MAX];
@ -2793,8 +2877,11 @@ int ambient_temperature(void)
pathcpy(hwmon_name, sizeof(hwmon_name), hwmon_entry->d_name);
dash = strrchr(hwmon_name, '_');
if (dash == 0)
if (dash == 0) {
/* LCOV_EXCL_START */
continue;
/* LCOV_EXCL_STOP */
}
if (strcmp(dash, "_input") != 0)
continue;
@ -2802,12 +2889,18 @@ int ambient_temperature(void)
/* read the temperature */
pathprint(path, sizeof(path), "/sys/class/hwmon/%s/%s", entry->d_name, hwmon_name);
if (sysattr(path, value, sizeof(value)) != 0)
if (sysattr(path, value, sizeof(value)) != 0) {
/* LCOV_EXCL_START */
continue;
/* LCOV_EXCL_STOP */
}
temp = strtol(value, &e, 10) / 1000;
if (*e != 0 && !isspace((unsigned char)*e))
if (*e != 0 && !isspace((unsigned char)*e)) {
/* LCOV_EXCL_START */
continue;
/* LCOV_EXCL_STOP */
}
/* cut the file name at "_input" */
*dash = 0;
@ -2815,15 +2908,19 @@ int ambient_temperature(void)
/* read the corresponding name */
pathprint(path, sizeof(path), "/sys/class/hwmon/%s/name", entry->d_name);
if (sysattr(path, name, sizeof(name)) != 0) {
/* LCOV_EXCL_START */
/* fallback to using the hwmon name */
pathcpy(name, sizeof(name), entry->d_name);
/* LCOV_EXCL_STOP */
}
/* read the corresponding label file */
pathprint(path, sizeof(path), "/sys/class/hwmon/%s/%s_label", entry->d_name, hwmon_name);
if (sysattr(path, label, sizeof(label)) != 0) {
/* LCOV_EXCL_START */
/* fallback to using the temp* name (e.g., temp1, temp2) */
pathcpy(label, sizeof(label), hwmon_name);
/* LCOV_EXCL_STOP */
}
log_tag("thermal:ambient:device:%s:%s:%s:%s:%ld\n", entry->d_name, name, hwmon_name, label, temp);
@ -2872,8 +2969,11 @@ int devmap(void)
#if HAVE_LINUX_DEVICE
char path[PATH_MAX];
DIR* d = opendir("/sys/block");
if (!d)
if (!d) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
struct dirent* dd;
while (1) {

View file

@ -3,6 +3,9 @@
# Run the Coverage test
#
# Ask root permissions at the start
sudo echo We are root
make distclean
if ! ./configure --enable-coverage --enable-sde; then
@ -17,6 +20,9 @@ if ! make check; then
exit 1
fi
# Root test for Btrfs
sudo make btrfscheck
# Run commands on a real array to test smartctl
sudo ./snapraid probe
sudo ./snapraid up
@ -24,7 +30,11 @@ sudo ./snapraid smart
sudo ./snapraid probe
sudo ./snapraid devices
sudo ./snapraid down
sudo ./snapraid test-downifup
if ! make lcov_capture lcov_html; then
exit 1
fi
# Remove root generated files
sudo make clean