diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index f057db45..98aa2e4e 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -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 : @@ -1978,6 +1984,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); diff --git a/cmdline/unix.c b/cmdline/unix.c index cd8cc3cb..ae9a25e5 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -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) { diff --git a/makecov.sh b/makecov.sh index eded9147..32923ac4 100755 --- a/makecov.sh +++ b/makecov.sh @@ -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