From bb3aae2f401498ec7bc192461837eb96d7925e2a Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Sat, 20 Dec 2025 18:21:38 +0100 Subject: [PATCH] Run smartctl only from selected paths --- HISTORY | 2 ++ cmdline/unix.c | 63 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/HISTORY b/HISTORY index 71e9a597..e5a7c8a4 100644 --- a/HISTORY +++ b/HISTORY @@ -3,6 +3,8 @@ SnapRAID HISTORY 13.1 WIP ======== + * Added detection of `smartctl` executable. Improves reliability when running + under `sudo` or environments where `/sbin` and `/usr/sbin` are not in PATH. * Avoided saving the content file when it was not strictly necessary. * More log tags for the `status` command [Tristan Teufel] * Added documentation of the tags used in the log file in the new diff --git a/cmdline/unix.c b/cmdline/unix.c index fe0e766d..78ee10ce 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -68,6 +68,30 @@ const char* stat_desc(struct stat* st) return "unknown"; } +static const char* smartctl_paths[] = { + /* Linux & BSD */ + "/usr/sbin/smartctl", + "/sbin/smartctl", + "/usr/local/sbin/smartctl", + "/usr/bin/smartctl", + "/usr/local/bin/smartctl", + /* macOS (Intel & Apple Silicon) */ + "/opt/homebrew/sbin/smartctl", + 0 +}; + +const char* find_smartctl(void) +{ + int i; + + for (i = 0; smartctl_paths[i]; ++i) { + if (access(smartctl_paths[i], X_OK) == 0) + return smartctl_paths[i]; + } + + return 0; +} + /** * Read a file from sys * @@ -1146,6 +1170,15 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64 char file[PATH_MAX]; FILE* f; int ret; + const char* x; + + x = find_smartctl(); + if (!x) { + /* LCOV_EXCL_START */ + log_fatal("Cannot find smartctl.\n"); + return -1; + /* LCOV_EXCL_STOP */ + } if (devresolve(device, file, sizeof(file)) != 0) { /* LCOV_EXCL_START */ @@ -1158,9 +1191,9 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64 if (smartctl[0]) { char option[PATH_MAX]; snprintf(option, sizeof(option), smartctl, file); - snprintf(cmd, sizeof(cmd), "smartctl -a %s", option); + snprintf(cmd, sizeof(cmd), "%s -a %s", x, option); } else { - snprintf(cmd, sizeof(cmd), "smartctl -a %s", file); + snprintf(cmd, sizeof(cmd), "%s -a %s", x, file); } log_tag("smartctl:%s:%s:run: %s\n", file, name, cmd); @@ -1218,6 +1251,15 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, int* p char file[PATH_MAX]; FILE* f; int ret; + const char* x; + + x = find_smartctl(); + if (!x) { + /* LCOV_EXCL_START */ + log_fatal("Cannot find smartctl.\n"); + return -1; + /* LCOV_EXCL_STOP */ + } if (devresolve(device, file, sizeof(file)) != 0) { /* LCOV_EXCL_START */ @@ -1230,9 +1272,9 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, int* p if (smartctl[0]) { char option[PATH_MAX]; snprintf(option, sizeof(option), smartctl, file); - snprintf(cmd, sizeof(cmd), "smartctl -n standby,3 -i %s", option); + snprintf(cmd, sizeof(cmd), "%s -n standby,3 -i %s", x, option); } else { - snprintf(cmd, sizeof(cmd), "smartctl -n standby,3 -i %s", file); + snprintf(cmd, sizeof(cmd), "%s -n standby,3 -i %s", x, file); } log_tag("smartctl:%s:%s:run: %s\n", file, name, cmd); @@ -1300,6 +1342,15 @@ static int devdown(dev_t device, const char* name, const char* smartctl) char file[PATH_MAX]; FILE* f; int ret; + const char* x; + + x = find_smartctl(); + if (!x) { + /* LCOV_EXCL_START */ + log_fatal("Cannot find smartctl.\n"); + return -1; + /* LCOV_EXCL_STOP */ + } if (devresolve(device, file, sizeof(file)) != 0) { /* LCOV_EXCL_START */ @@ -1312,9 +1363,9 @@ static int devdown(dev_t device, const char* name, const char* smartctl) if (smartctl[0]) { char option[PATH_MAX]; snprintf(option, sizeof(option), smartctl, file); - snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", option); + snprintf(cmd, sizeof(cmd), "%s -s standby,now %s", x, option); } else { - snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", file); + snprintf(cmd, sizeof(cmd), "%s -s standby,now %s", x, file); } log_tag("smartctl:%s:%s:run: %s\n", file, name, cmd);