Migrate Windows smartctl execution from _wpopen to os_popen and direct process spawning

This commit is contained in:
Andrea Mazzoleni 2026-09-14 15:40:54 +02:00
parent 9f48c87dd4
commit c1bcd6a24f
8 changed files with 433 additions and 134 deletions

View file

@ -335,6 +335,11 @@ extern int exit_sync_needed;
*/
#define SMART_MAX 128
/**
* Max smartctl custom option length.
*/
#define SMARTCTL_MAX 512
/**
* Smart ignore structure.
*/
@ -379,8 +384,8 @@ struct devinfo_struct {
uint64_t device; /**< Device ID. */
char name[PATH_MAX]; /**< Name of the disk combined with the split index if any */
char mount[PATH_MAX]; /**< Mount point or other contained directory. */
char smartctl[SMART_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMART_MAX]; /* Info options for smartctl. Empty means -a. */
char smartctl[SMARTCTL_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMARTCTL_MAX]; /* Info options for smartctl. Empty means -a. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Attributes to ignore */
char file[PATH_MAX]; /**< File device. */
#ifdef _WIN32

View file

@ -403,8 +403,8 @@ struct snapraid_extent {
struct snapraid_extra {
char name[PATH_MAX]; /**< Name of the disk. */
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
char smartctl[SMART_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMART_MAX]; /* Info options for smartctl. Empty means -a. */
char smartctl[SMARTCTL_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMARTCTL_MAX]; /* Info options for smartctl. Empty means -a. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
char uuid[UUID_MAX]; /**< UUID of the disk. They are probed during the config reading. */
char fstype[FSINFO_MAX]; /**< Filesystem type */
@ -442,8 +442,8 @@ struct snapraid_disk {
*/
struct fssnapshot_struct fss;
char smartctl[SMART_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMART_MAX]; /* Info options for smartctl. Empty means -a. */
char smartctl[SMARTCTL_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMARTCTL_MAX]; /* Info options for smartctl. Empty means -a. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
char uuid[UUID_MAX]; /**< UUID of the disk. They are probed during the config reading. */
char fstype[FSINFO_MAX]; /**< Filesystem type */
@ -585,8 +585,8 @@ struct snapraid_split {
struct snapraid_parity {
struct snapraid_split split_map[SPLIT_MAX]; /**< Parity splits. */
unsigned split_mac; /**< Number of parity splits. */
char smartctl[SMART_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMART_MAX]; /* Info options for smartctl. Empty means -a. */
char smartctl[SMARTCTL_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMARTCTL_MAX]; /* Info options for smartctl. Empty means -a. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
block_off_t total_blocks; /**< Number of total blocks. */
block_off_t free_blocks; /**< Number of free blocks at the last sync. */

View file

@ -248,7 +248,11 @@ static int base64_encode(const unsigned char* in, size_t in_len, char* out, size
*
* Runs a PowerShell one-liner via os_spawn() and captures the first line
* of stdout into `out` as UTF-8.
* `out` may be NULL when output is not needed.
* `out` may be 0 when output is not needed.
*
* Because os_spawn() captures stdout as a raw binary file descriptor without
* CRLF translation, callers must handle Windows \r\n explicitly. Here, \r\n
* is stripped using strpbrk() and strtrim().
*
* The command is executed using -EncodedCommand (Base64 UTF-16LE) to safely
* handle any shell metacharacters or quotes in paths and volume names.
@ -1117,61 +1121,145 @@ static int devstat(uint64_t device, const char* name, const char* wfile, uint64_
return 0;
}
#define ARGS_MAX 64
/**
* Build the absolute path to smartctl.exe located in the application directory.
*/
static int smartctl_executable(char* path, size_t size)
{
char conv_buf[CONV_MAX];
const wchar_t* dir = windows_exedir();
int ret;
if (!dir || dir[0] == 0) {
errno = ENOENT;
return -1;
}
ret = snprintf(path, size, "%ssmartctl.exe", u16tou8(conv_buf, dir));
if (ret < 0 || (size_t)ret >= size) {
errno = ENAMETOOLONG;
return -1;
}
return 0;
}
/**
* Get SMART attributes.
*/
static int devsmart(uint64_t device, const char* name, const char* smartctl, const char* smartctl_info, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* inter)
{
char conv_buf[CONV_MAX];
WCHAR cmd[PATH_MAX + SMART_MAX];
char smartctl_path[CONV_MAX];
char info_buf[SMARTCTL_MAX];
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
const char* argv[ARGS_MAX];
char file[128];
FILE* f;
unsigned argc;
OS_FILE* f;
int ret;
int count;
if (smartctl_executable(smartctl_path, sizeof(smartctl_path)) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Failed to build smartctl executable path.\n");
return -1;
/* LCOV_EXCL_STOP */
}
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
const char* info_opts = smartctl_info[0] ? smartctl_info : "-a";
/* if there is a custom smartctl command */
if (smartctl[0]) {
char option[SMART_MAX];
snprintf(option, sizeof(option), smartctl, file);
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" %s %s", windows_exedir(), info_opts, option);
} else {
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" %s %s", windows_exedir(), info_opts, file);
}
count = 0;
retry:
log_tag("smartctl:%s:%s:run: %s\n", file, name, u16tou8(conv_buf, cmd));
argc = 0;
argv[argc++] = smartctl_path;
f = _wpopen(cmd, L"rt");
pathcpy(info_buf, sizeof(info_buf), info_opts);
argc += argsplit(argv + argc, ARGS_MAX - argc, info_buf);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
if (count != 0) {
if (argc >= ARGS_MAX - 3) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = "-d";
argv[argc++] = "sat";
}
if (smartctl[0] && count == 0) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
log_tag("smartctl:%s:%s:run: %s [info: %s] %s\n", file, name, smartctl_path, info_opts, extra_args);
} else {
if (argc >= ARGS_MAX - 1) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = file;
if (count != 0)
log_tag("smartctl:%s:%s:run: %s [info: %s] -d sat %s\n", file, name, smartctl_path, info_opts, file);
else
log_tag("smartctl:%s:%s:run: %s [info: %s] %s\n", file, name, smartctl_path, info_opts, file);
}
argv[argc++] = 0;
f = os_popen(argv);
if (!f) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from popen).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:spawn\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] %s'.\n", smartctl_path, info_opts, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] -d sat %s'.\n", smartctl_path, info_opts, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] %s'.\n", smartctl_path, info_opts, file);
return -1;
/* LCOV_EXCL_STOP */
}
if (smartctl_attribute(f, file, name, smart, info, serial, family, model, inter) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
os_pclose(f);
log_tag("device:%s:%s:spawn\n", file, name);
return -1;
/* LCOV_EXCL_STOP */
}
ret = pclose(f);
ret = os_pclose(f);
log_tag("smartctl:%s:%s:ret: %x\n", file, name, ret);
if (ret == -1) {
if (!WIFEXITED(ret)) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from pclose).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:abort\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] %s' (not exited).\n", smartctl_path, info_opts, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] -d sat %s' (not exited).\n", smartctl_path, info_opts, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s [info: %s] %s' (not exited).\n", smartctl_path, info_opts, file);
return -1;
/* LCOV_EXCL_STOP */
}
@ -1189,21 +1277,18 @@ retry:
*
* Note that getting error 4 is instead very common, even with full info gathering.
*/
if ((ret == 0 || ret == 2)
if ((WEXITSTATUS(ret) == 0 || WEXITSTATUS(ret) == 2)
&& smart[SMART_POWER_ON_HOURS].raw == SMART_UNASSIGNED
&& info[INFO_SIZE] == SMART_UNASSIGNED
&& info[INFO_ROTATION_RATE] == SMART_UNASSIGNED
) {
/* retry using the "sat" type */
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" %s -d sat %s", windows_exedir(), info_opts, file);
++count;
goto retry;
}
}
/* store the smartctl return value */
smart[SMART_FLAGS].raw = ret;
smart[SMART_FLAGS].raw = WEXITSTATUS(ret);
return 0;
}
@ -1495,56 +1580,117 @@ static int devpower(uint64_t device, const char* name, const char* wfile)
*/
static int devprobe(uint64_t device, const char* name, const char* smartctl, const char* smartctl_info, int* power, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf)
{
char conv_buf[CONV_MAX];
WCHAR cmd[PATH_MAX + SMART_MAX];
char smartctl_path[CONV_MAX];
char info_buf[SMARTCTL_MAX];
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
const char* argv[ARGS_MAX];
char file[128];
FILE* f;
unsigned argc;
OS_FILE* f;
int ret;
int count;
if (smartctl_executable(smartctl_path, sizeof(smartctl_path)) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Failed to build smartctl executable path.\n");
return -1;
/* LCOV_EXCL_STOP */
}
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
const char* info_opts = smartctl_info[0] ? smartctl_info : "-a";
/* if there is a custom smartctl command */
if (smartctl[0]) {
char option[SMART_MAX];
snprintf(option, sizeof(option), smartctl, file);
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -n standby,3 %s %s", windows_exedir(), info_opts, option);
} else {
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -n standby,3 %s %s", windows_exedir(), info_opts, file);
}
count = 0;
retry:
log_tag("smartctl:%s:%s:run: %s\n", file, name, u16tou8(conv_buf, cmd));
argc = 0;
argv[argc++] = smartctl_path;
argv[argc++] = "-n";
argv[argc++] = "standby,3";
f = _wpopen(cmd, L"rt");
pathcpy(info_buf, sizeof(info_buf), info_opts);
argc += argsplit(argv + argc, ARGS_MAX - argc, info_buf);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
if (count != 0) {
if (argc >= ARGS_MAX - 3) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = "-d";
argv[argc++] = "sat";
}
if (smartctl[0] && count == 0) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
log_tag("smartctl:%s:%s:run: %s -n standby,3 [info: %s] %s\n", file, name, smartctl_path, info_opts, extra_args);
} else {
if (argc >= ARGS_MAX - 1) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = file;
if (count != 0)
log_tag("smartctl:%s:%s:run: %s -n standby,3 [info: %s] -d sat %s\n", file, name, smartctl_path, info_opts, file);
else
log_tag("smartctl:%s:%s:run: %s -n standby,3 [info: %s] %s\n", file, name, smartctl_path, info_opts, file);
}
argv[argc++] = 0;
f = os_popen(argv);
if (!f) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from popen).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:spawn\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s %s'.\n", smartctl_path, info_opts, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s -d sat %s'.\n", smartctl_path, info_opts, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s %s'.\n", smartctl_path, info_opts, file);
return -1;
/* LCOV_EXCL_STOP */
}
if (smartctl_attribute(f, file, name, smart, info, serial, family, model, interf) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
os_pclose(f);
log_tag("device:%s:%s:spawn\n", file, name);
return -1;
/* LCOV_EXCL_STOP */
}
ret = pclose(f);
ret = os_pclose(f);
log_tag("smartctl:%s:%s:ret: %x\n", file, name, ret);
if (ret == -1) {
if (!WIFEXITED(ret)) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from pclose).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:abort\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s %s' (not exited).\n", smartctl_path, info_opts, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s -d sat %s' (not exited).\n", smartctl_path, info_opts, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s -n standby,3 %s %s' (not exited).\n", smartctl_path, info_opts, file);
return -1;
/* LCOV_EXCL_STOP */
}
@ -1559,16 +1705,13 @@ retry:
*
* In such conditions we retry using the "sat" type, that often allows to proceed.
*/
if (ret == 2) {
/* retry using the "sat" type */
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -n standby,3 %s -d sat %s", windows_exedir(), info_opts, file);
if (WEXITSTATUS(ret) == 2) {
++count;
goto retry;
}
}
if (ret == 3) {
if (WEXITSTATUS(ret) == 3) {
log_tag("attr:%s:%s:power:standby\n", file, name);
*power = POWER_STANDBY;
} else {
@ -1577,7 +1720,7 @@ retry:
/* store the smartctl return value */
if (smart)
smart[SMART_FLAGS].raw = ret;
smart[SMART_FLAGS].raw = WEXITSTATUS(ret);
}
return 0;
@ -1588,54 +1731,105 @@ retry:
*/
static int devdown(uint64_t device, const char* name, const char* smartctl)
{
char conv_buf[CONV_MAX];
WCHAR cmd[PATH_MAX + SMART_MAX];
char smartctl_path[CONV_MAX];
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
const char* argv[ARGS_MAX];
char file[128];
FILE* f;
unsigned argc;
OS_FILE* f;
int ret;
int count;
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
/* if there is a custom smartctl command */
if (smartctl[0]) {
char option[SMART_MAX];
snprintf(option, sizeof(option), smartctl, file);
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -s standby,now %s", windows_exedir(), option);
} else {
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -s standby,now %s", windows_exedir(), file);
if (smartctl_executable(smartctl_path, sizeof(smartctl_path)) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Failed to build smartctl executable path.\n");
return -1;
/* LCOV_EXCL_STOP */
}
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
count = 0;
retry:
log_tag("smartctl:%s:%s:run: %s\n", file, name, u16tou8(conv_buf, cmd));
argc = 0;
argv[argc++] = smartctl_path;
argv[argc++] = "-s";
argv[argc++] = "standby,now";
f = _wpopen(cmd, L"rt");
if (count != 0) {
if (argc >= ARGS_MAX - 3) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = "-d";
argv[argc++] = "sat";
}
if (smartctl[0] && count == 0) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
log_tag("smartctl:%s:%s:run: %s -s standby,now %s\n", file, name, smartctl_path, extra_args);
} else {
if (argc >= ARGS_MAX - 1) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
return -1;
/* LCOV_EXCL_STOP */
}
argv[argc++] = file;
if (count != 0)
log_tag("smartctl:%s:%s:run: %s -s standby,now -d sat %s\n", file, name, smartctl_path, file);
else
log_tag("smartctl:%s:%s:run: %s -s standby,now %s\n", file, name, smartctl_path, file);
}
argv[argc++] = 0;
f = os_popen(argv);
if (!f) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from popen).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:spawn\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s'.\n", smartctl_path, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now -d sat %s'.\n", smartctl_path, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s'.\n", smartctl_path, file);
return -1;
/* LCOV_EXCL_STOP */
}
if (smartctl_flush(f, file, name) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
os_pclose(f);
log_tag("device:%s:%s:spawn\n", file, name);
return -1;
/* LCOV_EXCL_STOP */
}
ret = pclose(f);
ret = os_pclose(f);
log_tag("smartctl:%s:%s:ret: %x\n", file, name, ret);
if (ret == -1) {
if (!WIFEXITED(ret)) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:shell\n", file, name);
log_fatal(errno, "Failed to run '%s' (from pclose).\n", u16tou8(conv_buf, cmd));
log_tag("device:%s:%s:abort\n", file, name);
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s' (not exited).\n", smartctl_path, extra_args);
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now -d sat %s' (not exited).\n", smartctl_path, file);
else
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s' (not exited).\n", smartctl_path, file);
return -1;
/* LCOV_EXCL_STOP */
}
@ -1650,19 +1844,21 @@ retry:
*
* In such conditions we retry using the "sat" type, that often allows to proceed.
*/
if (ret == 2) {
/* retry using the "sat" type */
snwprintf(cmd, sizeof(cmd) / sizeof(cmd[0]), L"\"%lssmartctl.exe\" -s standby,now -d sat %s", windows_exedir(), file);
if (WEXITSTATUS(ret) == 2) {
++count;
goto retry;
}
}
if (ret != 0) {
if (WEXITSTATUS(ret) != 0) {
/* LCOV_EXCL_START */
log_tag("device:%s:%s:exit:%d\n", file, name, ret);
log_fatal(errno, "Failed to run '%s' with return code %xh.\n", u16tou8(conv_buf, cmd), ret);
log_tag("device:%s:%s:exit:%d\n", file, name, WEXITSTATUS(ret));
if (smartctl[0] && count == 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s' with return code %xh.\n", smartctl_path, extra_args, WEXITSTATUS(ret));
else if (count != 0)
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now -d sat %s' with return code %xh.\n", smartctl_path, file, WEXITSTATUS(ret));
else
log_fatal(EEXTERNAL, "Failed to run '%s -s standby,now %s' with return code %xh.\n", smartctl_path, file, WEXITSTATUS(ret));
return -1;
/* LCOV_EXCL_STOP */
}

View file

@ -1202,8 +1202,8 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
tommy_list_insert_tail(&state->extralist, &extra->node, extra);
} else if (strcmp(tag, "smartctl") == 0) {
char custom[PATH_MAX];
char parsed_smartctl[SMART_MAX];
char parsed_smartctl_info[SMART_MAX];
char parsed_smartctl[SMARTCTL_MAX];
char parsed_smartctl_info[SMARTCTL_MAX];
ret = sgettok(f, buffer, sizeof(buffer));
if (ret < 0) {

View file

@ -3285,7 +3285,7 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, const
unsigned argc = 0;
argv[argc++] = x;
char info_buf[SMART_MAX];
char info_buf[SMARTCTL_MAX];
pathcpy(info_buf, sizeof(info_buf), info_opts);
argc += argsplit(argv + argc, ARGS_MAX - argc, info_buf);
if (argc >= ARGS_MAX) {
@ -3296,9 +3296,11 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, const
}
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
if (smartctl[0]) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_args);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
@ -3454,7 +3456,7 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, const
argv[argc++] = "-n";
argv[argc++] = "standby,3";
char info_buf[SMART_MAX];
char info_buf[SMARTCTL_MAX];
pathcpy(info_buf, sizeof(info_buf), info_opts);
argc += argsplit(argv + argc, ARGS_MAX - argc, info_buf);
if (argc >= ARGS_MAX) {
@ -3465,9 +3467,11 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, const
}
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
if (smartctl[0]) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_args);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");
@ -3545,6 +3549,7 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, const
static int devdown(dev_t device, const char* name, const char* smartctl)
{
char extra_args[PATH_MAX];
char extra_split[PATH_MAX];
char file[PATH_MAX];
OS_FILE* f;
int ret;
@ -3573,7 +3578,8 @@ static int devdown(dev_t device, const char* name, const char* smartctl)
if (smartctl[0]) {
pathprint(extra_args, sizeof(extra_args), smartctl, file);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_args);
pathcpy(extra_split, sizeof(extra_split), extra_args);
argc += argsplit(argv + argc, ARGS_MAX - argc, extra_split);
if (argc >= ARGS_MAX) {
/* LCOV_EXCL_START */
log_fatal(EEXTERNAL, "Too many smartctl arguments.\n");