| 82 | |
| 83 | |
| 84 | hz::ExpectedVoid<SmartctlExecutorError> execute_smartctl(const std::string& device, const std::vector<std::string>& device_opts, |
| 85 | const std::vector<std::string>& command_options, |
| 86 | std::shared_ptr<CommandExecutor> smartctl_ex, std::string& smartctl_output) |
| 87 | { |
| 88 | // win32 doesn't have slashes in devices names. For others, check that slash is present. |
| 89 | if (!BuildEnv::is_kernel_family_windows()) { |
| 90 | const std::string::size_type pos = device.rfind('/'); // find basename |
| 91 | if (pos == std::string::npos) { |
| 92 | debug_out_error("app", DBG_FUNC_MSG << "Invalid device name \"" << device << "\".\n"); |
| 93 | return hz::Unexpected(SmartctlExecutorError::InvalidDevice, _("Invalid device name specified.")); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | |
| 98 | if (!smartctl_ex) // if it doesn't exist, create a default one |
| 99 | smartctl_ex = std::make_shared<SmartctlExecutor>(); |
| 100 | |
| 101 | auto smartctl_binary = get_smartctl_binary(); |
| 102 | |
| 103 | if (smartctl_binary.empty()) { |
| 104 | debug_out_error("app", DBG_FUNC_MSG << "Smartctl binary is not set in config.\n"); |
| 105 | return hz::Unexpected(SmartctlExecutorError::NoBinary, _("Smartctl binary is not specified in configuration.")); |
| 106 | } |
| 107 | |
| 108 | auto smartctl_def_options_str = hz::string_trim_copy(rconfig::get_data<std::string>("system/smartctl_options")); |
| 109 | std::vector<std::string> smartctl_options; |
| 110 | if (!smartctl_def_options_str.empty()) { |
| 111 | try { |
| 112 | smartctl_options = Glib::shell_parse_argv(smartctl_def_options_str); |
| 113 | } |
| 114 | catch(Glib::ShellError& e) |
| 115 | { |
| 116 | return hz::Unexpected(SmartctlExecutorError::InvalidCommandLine, _("Invalid command line specified.")); |
| 117 | } |
| 118 | } |
| 119 | smartctl_options.insert(smartctl_options.end(), device_opts.begin(), device_opts.end()); |
| 120 | smartctl_options.insert(smartctl_options.end(), command_options.begin(), command_options.end()); |
| 121 | smartctl_options.push_back(device); |
| 122 | |
| 123 | smartctl_ex->set_command(hz::fs_path_to_string(smartctl_binary), smartctl_options); |
| 124 | |
| 125 | if (!smartctl_ex->execute() || !smartctl_ex->get_error_msg().empty()) { |
| 126 | debug_out_warn("app", DBG_FUNC_MSG << "Smartctl binary did not execute cleanly.\n"); |
| 127 | |
| 128 | smartctl_output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str())); |
| 129 | |
| 130 | // check if it's a device permission error. |
| 131 | // Smartctl open device: /dev/sdb failed: Permission denied |
| 132 | if (app_regex_partial_match("/Smartctl open device.+Permission denied/mi", smartctl_output)) { |
| 133 | return hz::Unexpected(SmartctlExecutorError::PermissionDenied, _("Permission denied while opening device.")); |
| 134 | } |
| 135 | |
| 136 | // smartctl_output = smartctl_ex->get_stdout_str(); |
| 137 | return hz::Unexpected(SmartctlExecutorError::ExecutionError, smartctl_ex->get_error_msg()); |
| 138 | } |
| 139 | |
| 140 | // any_to_unix is needed for windows |
| 141 | smartctl_output = hz::string_trim_copy(hz::string_any_to_unix_copy(smartctl_ex->get_stdout_str())); |
no test coverage detected