1 /**************************************************************************
2  Copyright:
3       (C) 2008 - 2012  Alexander Shaduri <ashaduri 'at' gmail.com>
4  License: See LICENSE_gsmartcontrol.txt
5 ***************************************************************************/
6 /// \file
7 /// \author Alexander Shaduri
8 /// \ingroup applib
9 /// \weakgroup applib
10 /// @{
11 
12 #ifndef SELFTEST_H
13 #define SELFTEST_H
14 
15 #include <glibmm.h>
16 #include <string>
17 
18 #include "hz/cstdint.h"
19 #include "hz/intrusive_ptr.h"
20 
21 #include "storage_device.h"
22 #include "cmdex_sync.h"
23 
24 
25 
26 /// SMART self-test runner.
27 class SelfTest : public hz::intrusive_ptr_referenced {
28 	public:
29 
30 		/// Test type
31 		enum test_t {
32 			type_ioffline,  ///< Immediate offline, not supported
33 			type_short,  ///< Short self-test
34 			type_long,  ///< Extended (a.k.a. long) self-test
35 			type_conveyance  ///< Conveyance self-test
36 		};
37 
38 
39 		/// Get displayable name for a test type
get_test_name(test_t t)40 		static std::string get_test_name(test_t t)
41 		{
42 			switch (t) {
43 				case type_ioffline: return "Immediate Offline Test";
44 				case type_short: return "Short Self-test";
45 				case type_long: return "Extended Self-test";
46 				case type_conveyance: return "Conveyance Self-test";
47 			};
48 			return "[error]";
49 		}
50 
51 
52 		/// Constructor. \c drive must have the capabilities present in its properties.
SelfTest(StorageDeviceRefPtr drive,test_t type)53 		SelfTest(StorageDeviceRefPtr drive, test_t type)
54 			: drive_(drive), type_(type)
55 		{
56 			clear();
57 		}
58 
59 
60 		/// Clear results of previous test
clear()61 		void clear()
62 		{
63 			status_ = StorageSelftestEntry::status_unknown;
64 			remaining_percent_ = -1;
65 			last_seen_percent_ = -1;
66 			total_duration_ = -1;
67 			poll_in_seconds_ = -1;
68 		}
69 
70 
71 		/// Check if the test is currently active
is_active()72 		bool is_active() const
73 		{
74 			return (status_ == StorageSelftestEntry::status_in_progress);
75 		}
76 
77 
78 		/// Get remaining time percent until the test completion.
79 		/// \return -1 if N/A or unknown.
get_remaining_percent()80 		int8_t get_remaining_percent() const
81 		{
82 			return remaining_percent_;
83 		}
84 
85 
86 		/// Get estimated time of completion for the test.
87 		/// \return -1 if N/A or unknown. Note that 0 is a valid value.
88 		int64_t get_remaining_seconds() const;
89 
90 
91 		/// Get test type
get_test_type()92 		test_t get_test_type() const
93 		{
94 			return type_;
95 		}
96 
97 
98 		/// Get test status
get_status()99 		StorageSelftestEntry::status_t get_status() const
100 		{
101 			return status_;
102 		}
103 
104 
105 		/// Get the number of seconds after which the caller should call update().
get_poll_in_seconds()106 		int64_t get_poll_in_seconds() const
107 		{
108 			return poll_in_seconds_;
109 		}
110 
111 
112 		/// Get a constant "test duration during idle" capability drive's stored capabilities. -1 if N/A.
113 		int64_t get_min_duration_seconds() const;
114 
115 
116 		/// Gets the current test type support status from drive's stored capabilities.
117 		bool is_supported() const;
118 
119 
120 		/// Start the test.
121 		/// \return error message on error, empty string on success.
122 		std::string start(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
123 
124 
125 		/// Abort the running test.
126 		/// \return error message on error, empty string on success.
127 		std::string force_stop(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
128 
129 
130 		/// Update status variables. The user should call this every get_poll_in_seconds() seconds.
131 		/// \return error message on error, empty string on success.
132 		std::string update(hz::intrusive_ptr<CmdexSync> smartctl_ex = 0);
133 
134 
135 	private:
136 
137 		StorageDeviceRefPtr drive_;  ///< Drive to run the tests on
138 		test_t type_;  ///< Test type
139 
140 		// status variables:
141 		StorageSelftestEntry::status_t status_;  ///< Current status of the test as reported by the drive
142 		int8_t remaining_percent_;  ///< Remaining %. 0 means unknown, -1 means N/A. This is set to 100 on start.
143 		int8_t last_seen_percent_;  ///< Last reported %, to detect changes in percentage (needed for timer update).
144 		mutable int64_t total_duration_;  ///< Total duration needed for the test, as reported by the drive. Constant. This variable acts as a cache.
145 		int64_t poll_in_seconds_;  ///< The user is asked to poll after this much seconds have passed.
146 
147 		Glib::Timer timer_;  ///< Counts time since the last percent change
148 
149 };
150 
151 
152 
153 /// A reference-counting pointer to SelfTest
154 typedef hz::intrusive_ptr<SelfTest> SelfTestPtr;
155 
156 
157 
158 
159 #endif
160 
161 /// @}
162