]>
Commit | Line | Data |
---|---|---|
832b75ed GG |
1 | /* |
2 | * utility.h | |
3 | * | |
4 | * Home page of code is: http://smartmontools.sourceforge.net | |
5 | * | |
2127e193 GI |
6 | * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> |
7 | * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net> | |
832b75ed GG |
8 | * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2, or (at your option) | |
13 | * any later version. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * (for example COPYING); if not, write to the Free | |
17 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | * | |
19 | * This code was originally developed as a Senior Thesis by Michael Cornwell | |
20 | * at the Concurrent Systems Laboratory (now part of the Storage Systems | |
21 | * Research Center), Jack Baskin School of Engineering, University of | |
22 | * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ | |
23 | * | |
24 | */ | |
25 | ||
26 | #ifndef UTILITY_H_ | |
27 | #define UTILITY_H_ | |
28 | ||
2127e193 | 29 | #define UTILITY_H_CVSID "$Id: utility.h 2848 2009-07-18 20:14:38Z chrfranke $" |
832b75ed GG |
30 | |
31 | #include <time.h> | |
32 | #include <sys/types.h> // for regex.h (according to POSIX) | |
33 | #include <regex.h> | |
2127e193 GI |
34 | #include <stdarg.h> |
35 | #include <stdio.h> | |
36 | #include <string.h> | |
37 | #include <string> | |
38 | ||
39 | #if !defined(__GNUC__) && !defined(__attribute__) | |
40 | #define __attribute__(x) /**/ | |
41 | #endif | |
42 | ||
43 | // Make version information string | |
44 | std::string format_version_info(const char * prog_name, bool full = false); | |
45 | ||
46 | // return (v)sprintf() formated std::string | |
47 | std::string strprintf(const char * fmt, ...) | |
48 | __attribute__ ((format (printf, 1, 2))); | |
49 | std::string vstrprintf(const char * fmt, va_list ap); | |
832b75ed GG |
50 | |
51 | #ifndef HAVE_WORKING_SNPRINTF | |
52 | // Substitute by safe replacement functions | |
2127e193 GI |
53 | int safe_snprintf(char *buf, int size, const char *fmt, ...) |
54 | __attribute__ ((format (printf, 3, 4))); | |
832b75ed GG |
55 | int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap); |
56 | #define snprintf safe_snprintf | |
57 | #define vsnprintf safe_vsnprintf | |
58 | #endif | |
59 | ||
2127e193 GI |
60 | #ifndef HAVE_STRTOULL |
61 | // Replacement for missing strtoull() (Linux with libc < 6, MSVC) | |
62 | uint64_t strtoull(const char * p, char * * endp, int base); | |
63 | #endif | |
64 | ||
832b75ed GG |
65 | // Utility function prints current date and time and timezone into a |
66 | // character buffer of length>=64. All the fuss is needed to get the | |
67 | // right timezone info (sigh). | |
68 | #define DATEANDEPOCHLEN 64 | |
69 | void dateandtimezone(char *buffer); | |
70 | // Same, but for time defined by epoch tval | |
71 | void dateandtimezoneepoch(char *buffer, time_t tval); | |
72 | ||
832b75ed GG |
73 | // like printf() except that we can control it better. Note -- |
74 | // although the prototype is given here in utility.h, the function | |
75 | // itself is defined differently in smartctl and smartd. So the | |
76 | // function definition(s) are in smartd.c and in smartctl.c. | |
4d59bff9 | 77 | void pout(const char *fmt, ...) |
832b75ed GG |
78 | __attribute__ ((format (printf, 1, 2))); |
79 | ||
80 | // replacement for perror() with redirected output. | |
81 | void syserror(const char *message); | |
82 | ||
832b75ed GG |
83 | // Function for processing -r option in smartctl and smartd |
84 | int split_report_arg(char *s, int *i); | |
85 | // Function for processing -c option in smartctl and smartd | |
86 | int split_report_arg2(char *s, int *i); | |
a37e7145 | 87 | |
832b75ed | 88 | // Function for processing -t selective... option in smartctl |
a37e7145 | 89 | int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode); |
832b75ed GG |
90 | |
91 | ||
92 | // Guess device type (ata or scsi) based on device name | |
93 | // Guessing will now use Controller Type defines below | |
94 | ||
2127e193 GI |
95 | // Moved to C++ interface |
96 | //int guess_device_type(const char * dev_name); | |
832b75ed GG |
97 | |
98 | // Create and return the list of devices to probe automatically | |
99 | // if the DEVICESCAN option is in the smartd config file | |
2127e193 GI |
100 | // Moved to C++ interface |
101 | //int make_device_names (char ***devlist, const char* name); | |
102 | ||
103 | // Replacement for exit(status) | |
104 | // (exit is not compatible with C++ destructors) | |
105 | #define EXIT(status) { throw (int)(status); } | |
832b75ed GG |
106 | |
107 | ||
2127e193 | 108 | #ifdef OLD_INTERFACE |
832b75ed GG |
109 | |
110 | // replacement for calloc() that tracks memory usage | |
111 | void *Calloc(size_t nmemb, size_t size); | |
112 | ||
113 | // Utility function to free memory | |
4d59bff9 GG |
114 | void *FreeNonZero1(void* address, int size, int whatline, const char* file); |
115 | ||
116 | // Typesafe version of above | |
117 | template <class T> | |
118 | inline T * FreeNonZero(T * address, int size, int whatline, const char* file) | |
119 | { return (T *)FreeNonZero1((void *)address, size, whatline, file); } | |
832b75ed GG |
120 | |
121 | // A custom version of strdup() that keeps track of how much memory is | |
122 | // being allocated. If mustexist is set, it also throws an error if we | |
123 | // try to duplicate a NULL string. | |
a37e7145 | 124 | char *CustomStrDup(const char *ptr, int mustexist, int whatline, const char* file); |
832b75ed GG |
125 | |
126 | // To help with memory checking. Use when it is known that address is | |
127 | // NOT null. | |
4d59bff9 GG |
128 | void *CheckFree1(void *address, int whatline, const char* file); |
129 | ||
130 | // Typesafe version of above | |
131 | template <class T> | |
132 | inline T * CheckFree(T * address, int whatline, const char* file) | |
133 | { return (T *)CheckFree1((void *)address, whatline, file); } | |
832b75ed | 134 | |
2127e193 GI |
135 | #endif // OLD_INTERFACE |
136 | ||
832b75ed GG |
137 | // This function prints either to stdout or to the syslog as needed |
138 | ||
139 | // [From GLIBC Manual: Since the prototype doesn't specify types for | |
140 | // optional arguments, in a call to a variadic function the default | |
141 | // argument promotions are performed on the optional argument | |
142 | // values. This means the objects of type char or short int (whether | |
143 | // signed or not) are promoted to either int or unsigned int, as | |
144 | // appropriate.] | |
4d59bff9 | 145 | void PrintOut(int priority, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); |
832b75ed GG |
146 | |
147 | // run time, determine byte ordering | |
148 | int isbigendian(); | |
149 | ||
150 | // This value follows the peripheral device type value as defined in | |
151 | // SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in | |
152 | // the ATA standard for packet devices to define the device type. | |
153 | const char *packetdevicetype(int type); | |
154 | ||
2127e193 GI |
155 | // Moved to C++ interface |
156 | //int deviceopen(const char *pathname, char *type); | |
832b75ed | 157 | |
2127e193 | 158 | //int deviceclose(int fd); |
832b75ed GG |
159 | |
160 | // Optional functions of os_*.c | |
161 | #ifdef HAVE_GET_OS_VERSION_STR | |
162 | // Return build host and OS version as static string | |
2127e193 | 163 | //const char * get_os_version_str(void); |
832b75ed GG |
164 | #endif |
165 | ||
2127e193 GI |
166 | // returns true if any of the n bytes are nonzero, else zero. |
167 | bool nonempty(const void * data, int size); | |
832b75ed GG |
168 | |
169 | // needed to fix glibc bug | |
170 | void FixGlibcTimeZoneBug(); | |
171 | ||
172 | // convert time in msec to a text string | |
173 | void MsecToText(unsigned int msec, char *txt); | |
174 | ||
2127e193 GI |
175 | // Wrapper class for a raw data buffer |
176 | class raw_buffer | |
177 | { | |
178 | public: | |
179 | explicit raw_buffer(unsigned sz, unsigned char val = 0) | |
180 | : m_data(new unsigned char[sz]), | |
181 | m_size(sz) | |
182 | { memset(m_data, val, m_size); } | |
183 | ||
184 | ~raw_buffer() | |
185 | { delete [] m_data; } | |
186 | ||
187 | unsigned size() const | |
188 | { return m_size; } | |
189 | ||
190 | unsigned char * data() | |
191 | { return m_data; } | |
192 | const unsigned char * data() const | |
193 | { return m_data; } | |
194 | ||
195 | private: | |
196 | unsigned char * m_data; | |
197 | unsigned m_size; | |
198 | ||
199 | raw_buffer(const raw_buffer &); | |
200 | void operator=(const raw_buffer &); | |
201 | }; | |
202 | ||
203 | /// Wrapper class for FILE *. | |
204 | class stdio_file | |
205 | { | |
206 | public: | |
207 | explicit stdio_file(FILE * f = 0, bool owner = false) | |
208 | : m_file(f), m_owner(owner) { } | |
209 | ||
210 | stdio_file(const char * name, const char * mode) | |
211 | : m_file(fopen(name, mode)), m_owner(true) { } | |
212 | ||
213 | ~stdio_file() | |
214 | { | |
215 | if (m_file && m_owner) | |
216 | fclose(m_file); | |
217 | } | |
218 | ||
219 | bool open(const char * name, const char * mode) | |
220 | { | |
221 | m_file = fopen(name, mode); | |
222 | m_owner = true; | |
223 | return !!m_file; | |
224 | } | |
225 | ||
226 | void open(FILE * f, bool owner = false) | |
227 | { | |
228 | m_file = f; | |
229 | m_owner = owner; | |
230 | } | |
231 | ||
232 | bool close() | |
233 | { | |
234 | if (!m_file) | |
235 | return true; | |
236 | bool ok = !ferror(m_file); | |
237 | if (fclose(m_file)) | |
238 | ok = false; | |
239 | m_file = 0; | |
240 | return ok; | |
241 | } | |
242 | ||
243 | operator FILE * () | |
244 | { return m_file; } | |
245 | ||
246 | bool operator!() const | |
247 | { return !m_file; } | |
248 | ||
249 | private: | |
250 | FILE * m_file; | |
251 | bool m_owner; | |
252 | ||
253 | stdio_file(const stdio_file &); | |
254 | void operator=(const stdio_file &); | |
255 | }; | |
256 | ||
257 | /// Wrapper class for regex(3). | |
258 | /// Supports copy & assignment and is compatible with STL containers. | |
259 | class regular_expression | |
260 | { | |
261 | public: | |
262 | // Construction & assignment | |
263 | regular_expression(); | |
264 | ||
265 | regular_expression(const char * pattern, int flags); | |
266 | ||
267 | ~regular_expression(); | |
268 | ||
269 | regular_expression(const regular_expression & x); | |
270 | ||
271 | regular_expression & operator=(const regular_expression & x); | |
272 | ||
273 | /// Set and compile new pattern, return false on error. | |
274 | bool compile(const char * pattern, int flags); | |
275 | ||
276 | // Get pattern from last compile(). | |
277 | const char * get_pattern() const | |
278 | { return m_pattern.c_str(); } | |
279 | ||
280 | /// Get error message from last compile(). | |
281 | const char * get_errmsg() const | |
282 | { return m_errmsg.c_str(); } | |
283 | ||
284 | // Return true if pattern is not set or bad. | |
285 | bool empty() const | |
286 | { return (m_pattern.empty() || !m_errmsg.empty()); } | |
287 | ||
288 | /// Return true if substring matches pattern | |
289 | bool match(const char * str, int flags = 0) const | |
290 | { return !regexec(&m_regex_buf, str, 0, (regmatch_t*)0, flags); } | |
291 | ||
292 | /// Return true if full string matches pattern | |
293 | bool full_match(const char * str, int flags = 0) const | |
294 | { | |
295 | regmatch_t range; | |
296 | return ( !regexec(&m_regex_buf, str, 1, &range, flags) | |
297 | && range.rm_so == 0 && range.rm_eo == (int)strlen(str)); | |
298 | } | |
299 | ||
300 | /// Return true if substring matches pattern, fill regmatch_t array. | |
301 | bool execute(const char * str, unsigned nmatch, regmatch_t * pmatch, int flags = 0) const | |
302 | { return !regexec(&m_regex_buf, str, nmatch, pmatch, flags); } | |
303 | ||
304 | private: | |
305 | std::string m_pattern; | |
306 | int m_flags; | |
307 | regex_t m_regex_buf; | |
308 | std::string m_errmsg; | |
309 | ||
310 | void free_buf(); | |
311 | void copy(const regular_expression & x); | |
312 | bool compile(); | |
313 | }; | |
832b75ed GG |
314 | |
315 | // macros to control printing | |
2127e193 GI |
316 | #define PRINT_ON(control) {if (control->printing_switchable) control->dont_print=false;} |
317 | #define PRINT_OFF(control) {if (control->printing_switchable) control->dont_print=true;} | |
832b75ed | 318 | |
2127e193 | 319 | #ifdef OLD_INTERFACE |
832b75ed GG |
320 | // possible values for controller_type in extern.h |
321 | #define CONTROLLER_UNKNOWN 0x00 | |
322 | #define CONTROLLER_ATA 0x01 | |
323 | #define CONTROLLER_SCSI 0x02 | |
324 | #define CONTROLLER_3WARE 0x03 // set by -d option, but converted to one of three types below | |
325 | #define CONTROLLER_3WARE_678K 0x04 // NOT set by guess_device_type() | |
326 | #define CONTROLLER_3WARE_9000_CHAR 0x05 // set by guess_device_type() | |
327 | #define CONTROLLER_3WARE_678K_CHAR 0x06 // set by guess_device_type() | |
328 | #define CONTROLLER_MARVELL_SATA 0x07 // SATA drives behind Marvell controllers | |
4d59bff9 GG |
329 | #define CONTROLLER_SAT 0x08 // SATA device behind a SCSI ATA Translation (SAT) layer |
330 | #define CONTROLLER_HPT 0x09 // SATA drives behind HighPoint Raid controllers | |
ba59cff1 | 331 | #define CONTROLLER_CCISS 0x10 // CCISS controller |
a37e7145 | 332 | #define CONTROLLER_PARSEDEV 0x11 // "smartctl -r ataioctl,2 ..." output parser pseudo-device |
2127e193 GI |
333 | #define CONTROLLER_USBCYPRESS 0x12 // ATA device behind Cypress USB bridge |
334 | #define CONTROLLER_ARECA 0x13 // Areca controller | |
335 | #endif | |
832b75ed GG |
336 | |
337 | #endif |