4 * Home page of code is: http://www.smartmontools.org
7 * Copyright (C) 2002-12 Bruce Allen
8 * Copyright (C) 2008-16 Christian Franke
10 * Copyright (C) 2002-12 Bruce Allen <smartmontools-support@lists.sourceforge.net>
11 * Copyright (C) 2008-15 Christian Franke <smartmontools-support@lists.sourceforge.net>
12 >>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
13 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
20 * You should have received a copy of the GNU General Public License
21 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
23 * This code was originally developed as a Senior Thesis by Michael Cornwell
24 * at the Concurrent Systems Laboratory (now part of the Storage Systems
25 * Research Center), Jack Baskin School of Engineering, University of
26 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
30 // THIS FILE IS INTENDED FOR UTILITY ROUTINES THAT ARE APPLICABLE TO
31 // BOTH SCSI AND ATA DEVICES, AND THAT MAY BE USED IN SMARTD,
48 #include <mbstring.h> // _mbsinc()
53 #include "svnversion.h"
58 #include "dev_interface.h"
61 const char * utility_cpp_cvsid
= "$Id: utility.cpp 4309 2016-04-24 14:59:15Z chrfranke $"
63 const char * utility_cpp_cvsid
= "$Id: utility.cpp 4031 2015-01-01 10:47:48Z chrfranke $"
64 >>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
65 UTILITY_H_CVSID INT64_H_CVSID
;
67 const char * packet_types
[] = {
68 "Direct-access (disk)",
69 "Sequential-access (tape)",
72 "Write-once (optical disk)",
75 "Optical memory (optical disk)",
78 "Graphic arts pre-press (10)",
79 "Graphic arts pre-press (11)",
82 "Reduced block command (simplified disk)",
83 "Optical card reader/writer"
86 // BUILD_INFO can be provided by package maintainers
88 #define BUILD_INFO "(local build)"
91 // Make version information string
92 std::string
format_version_info(const char * prog_name
, bool full
/*= false*/)
94 std::string info
= strprintf(
95 "%s " PACKAGE_VERSION
" "
96 #ifdef SMARTMONTOOLS_SVN_REV
97 SMARTMONTOOLS_SVN_DATE
" r" SMARTMONTOOLS_SVN_REV
99 "(build date " __DATE__
")" // checkout without expansion of Id keywords
101 " [%s] " BUILD_INFO
"\n"
103 "Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org\n",
105 "Copyright (C) 2002-15, Bruce Allen, Christian Franke, www.smartmontools.org\n",
106 >>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
107 prog_name
, smi()->get_os_version_str().c_str()
114 info
+= " comes with ABSOLUTELY NO WARRANTY. This is free\n"
115 "software, and you are welcome to redistribute it under\n"
116 "the terms of the GNU General Public License; either\n"
117 "version 2, or (at your option) any later version.\n"
118 "See http://www.gnu.org for further details.\n"
120 "smartmontools release " PACKAGE_VERSION
121 " dated " SMARTMONTOOLS_RELEASE_DATE
" at " SMARTMONTOOLS_RELEASE_TIME
"\n"
122 #ifdef SMARTMONTOOLS_SVN_REV
123 "smartmontools SVN rev " SMARTMONTOOLS_SVN_REV
124 " dated " SMARTMONTOOLS_SVN_DATE
" at " SMARTMONTOOLS_SVN_TIME
"\n"
126 "smartmontools SVN rev is unknown\n"
128 "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST
"\n"
129 "smartmontools build with: "
130 #if __cplusplus > 201402
132 #elif __cplusplus > 201103
134 #elif __cplusplus > 199711
139 #if defined(__GNUC__) && defined(__VERSION__) // works also with CLang
143 "smartmontools configure arguments:"
145 info
+= (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS
) > 1 ?
146 SMARTMONTOOLS_CONFIGURE_ARGS
: " [no arguments given]");
152 // Solaris only: Get site-default timezone. This is called from
153 // UpdateTimezone() when TZ environment variable is unset at startup.
154 #if defined (__SVR4) && defined (__sun)
155 static const char *TIMEZONE_FILE
= "/etc/TIMEZONE";
157 static char *ReadSiteDefaultTimezone(){
163 fp
= fopen(TIMEZONE_FILE
, "r");
164 if(fp
== NULL
) return NULL
;
165 while(fgets(buf
, sizeof(buf
), fp
)) {
166 if (strncmp(buf
, "TZ=", 3)) // searches last "TZ=" line
169 if (buf
[n
] == '\n') buf
[n
] = 0;
178 // Make sure that this executable is aware if the user has changed the
179 // time-zone since the last time we polled devices. The cannonical
180 // example is a user who starts smartd on a laptop, then flies across
181 // time-zones with a laptop, and then changes the timezone, WITHOUT
182 // restarting smartd. This is a work-around for a bug in
183 // GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and
184 // thanks to Ian Redfern for posting a workaround.
186 // Please refer to the smartd manual page, in the section labeled LOG
187 // TIMESTAMP TIMEZONE.
188 void FixGlibcTimeZoneBug(){
191 putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
193 putenv((char *)"TZ");
200 putenv("TZ="); // empty value removes TZ, putenv("TZ") does nothing
203 #elif defined (__SVR4) && defined (__sun)
204 // In Solaris, putenv("TZ=") sets null string and invalid timezone.
205 // putenv("TZ") does nothing. With invalid TZ, tzset() do as if
206 // TZ=GMT. With TZ unset, /etc/TIMEZONE will be read only _once_ at
207 // first tzset() call. Conclusion: Unlike glibc, dynamic
208 // configuration of timezone can be done only by changing actual
209 // value of TZ environment value.
210 enum tzstate
{ NOT_CALLED_YET
, USER_TIMEZONE
, TRACK_TIMEZONE
};
211 static enum tzstate state
= NOT_CALLED_YET
;
213 static struct stat prev_stat
;
214 static char *prev_tz
;
215 struct stat curr_stat
;
218 if(state
== NOT_CALLED_YET
) {
220 state
= USER_TIMEZONE
; // use supplied timezone
222 state
= TRACK_TIMEZONE
;
223 if(stat(TIMEZONE_FILE
, &prev_stat
)) {
224 state
= USER_TIMEZONE
; // no TZ, no timezone file; use GMT forever
226 prev_tz
= ReadSiteDefaultTimezone(); // track timezone file change
227 if(prev_tz
) putenv(prev_tz
);
231 } else if(state
== TRACK_TIMEZONE
) {
232 if(stat(TIMEZONE_FILE
, &curr_stat
) == 0
233 && (curr_stat
.st_ctime
!= prev_stat
.st_ctime
234 || curr_stat
.st_mtime
!= prev_stat
.st_mtime
)) {
235 // timezone file changed
236 curr_tz
= ReadSiteDefaultTimezone();
239 if(prev_tz
) free(prev_tz
);
240 prev_tz
= curr_tz
; prev_stat
= curr_stat
;
246 // OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED. PLEASE TRY TO
247 // KEEP THEM INDEPENDENT.
252 // Fix strings in tzname[] to avoid long names with non-ascii characters.
253 // If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
254 // national language timezone names returned by GetTimezoneInformation().
255 static char * fixtzname(char * dest
, int destsize
, const char * src
)
258 while (src
[i
] && j
< destsize
-1) {
259 int i2
= (const char *)_mbsinc((const unsigned char *)src
+i
) - src
;
261 i
= i2
; // Ignore multibyte chars
263 if ('A' <= src
[i
] && src
[i
] <= 'Z')
264 dest
[j
++] = src
[i
]; // "Pacific Standard Time" => "PST"
275 // This value follows the peripheral device type value as defined in
276 // SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
277 // the ATA standard for packet devices to define the device type.
278 const char *packetdevicetype(int type
){
280 return packet_types
[type
];
288 // Runtime check of byte ordering, throws if different from isbigendian().
289 static void check_endianness()
292 // Force compile error if int type is not 32bit.
293 unsigned char c
[sizeof(unsigned) == 4 ? 4 : -1];
299 case 0x01020304: big
= 1; break;
300 case 0x04030201: big
= 0; break;
303 if (big
!= (isbigendian() ? 1 : 0))
304 throw std::logic_error("CPU endianness does not match compile time test");
307 // Utility function prints date and time and timezone into a character
308 // buffer of length>=64. All the fuss is needed to get the right
309 // timezone info (sigh).
310 void dateandtimezoneepoch(char *buffer
, time_t tval
){
312 const char *timezonename
;
313 char datebuffer
[DATEANDEPOCHLEN
];
316 FixGlibcTimeZoneBug();
318 // Get the time structure. We need this to determine if we are in
319 // daylight savings time or not.
320 tmval
=localtime(&tval
);
322 // Convert to an ASCII string, put in datebuffer
323 // same as: asctime_r(tmval, datebuffer);
324 strncpy(datebuffer
, asctime(tmval
), DATEANDEPOCHLEN
);
325 datebuffer
[DATEANDEPOCHLEN
-1]='\0';
328 lenm1
=strlen(datebuffer
)-1;
329 datebuffer
[lenm1
>=0?lenm1
:0]='\0';
331 // correct timezone name
332 if (tmval
->tm_isdst
==0)
333 // standard time zone
334 timezonename
=tzname
[0];
335 else if (tmval
->tm_isdst
>0)
336 // daylight savings in effect
337 timezonename
=tzname
[1];
339 // unable to determine if daylight savings in effect
343 // Fix long non-ascii timezone names
344 // cppcheck-suppress variableScope
345 char tzfixbuf
[6+1] = "";
347 timezonename
=fixtzname(tzfixbuf
, sizeof(tzfixbuf
), timezonename
);
350 // Finally put the information into the buffer as needed.
351 snprintf(buffer
, DATEANDEPOCHLEN
, "%s %s", datebuffer
, timezonename
);
356 // Date and timezone gets printed into string pointed to by buffer
357 void dateandtimezone(char *buffer
){
359 // Get the epoch (time in seconds since Jan 1 1970)
360 time_t tval
=time(NULL
);
362 dateandtimezoneepoch(buffer
, tval
);
366 // A replacement for perror() that sends output to our choice of
367 // printing. If errno not set then just print message.
368 void syserror(const char *message
){
371 // Get the correct system error message:
372 const char *errormessage
=strerror(errno
);
374 // Check that caller has handed a sensible string, and provide
375 // appropriate output. See perrror(3) man page to understand better.
376 if (message
&& *message
)
377 pout("%s: %s\n",message
, errormessage
);
379 pout("%s\n",errormessage
);
381 else if (message
&& *message
)
382 pout("%s\n",message
);
387 // Check regular expression for non-portable features.
389 // POSIX extended regular expressions interpret unmatched ')' ordinary:
390 // "The close-parenthesis shall be considered special in this context
391 // only if matched with a preceding open-parenthesis."
393 // GNU libc and BSD libc support unmatched ')', Cygwin reports an error.
395 // POSIX extended regular expressions do not define empty subexpressions:
396 // "A vertical-line appearing first or last in an ERE, or immediately following
397 // a vertical-line or a left-parenthesis, or immediately preceding a
398 // right-parenthesis, produces undefined results."
400 // GNU libc and Cygwin support empty subexpressions, BSD libc reports an error.
402 static const char * check_regex(const char * pattern
)
407 for (int i
= 0; (c
= pattern
[i
]); i
++) {
417 if (pattern
[++i
] == '^')
421 while ((c
= pattern
[i
]) && c
!= ']')
428 // Check "(...)" nesting
431 else if (c
== ')' && --level
< 0)
432 return "Unmatched ')'";
434 // Check for leading/trailing '|' or "||", "|)", "|$", "(|", "^|"
436 if ( (c
== '|' && ( i
== 0 || !(c1
= pattern
[i
+1])
437 || c1
== '|' || c1
== ')' || c1
== '$'))
438 || ((c
== '(' || c
== '^') && pattern
[i
+1] == '|') )
439 return "Empty '|' subexpression";
442 return (const char *)0;
445 // Wrapper class for regex(3)
447 regular_expression::regular_expression()
450 memset(&m_regex_buf
, 0, sizeof(m_regex_buf
));
453 regular_expression::regular_expression(const char * pattern
, int flags
,
454 bool throw_on_error
/*= true*/)
456 memset(&m_regex_buf
, 0, sizeof(m_regex_buf
));
457 if (!compile(pattern
, flags
) && throw_on_error
)
458 throw std::runtime_error(strprintf(
459 "error in regular expression \"%s\": %s",
460 m_pattern
.c_str(), m_errmsg
.c_str()));
463 regular_expression::~regular_expression()
468 regular_expression::regular_expression(const regular_expression
& x
)
470 memset(&m_regex_buf
, 0, sizeof(m_regex_buf
));
474 regular_expression
& regular_expression::operator=(const regular_expression
& x
)
481 void regular_expression::free_buf()
483 if (nonempty(&m_regex_buf
, sizeof(m_regex_buf
))) {
484 regfree(&m_regex_buf
);
485 memset(&m_regex_buf
, 0, sizeof(m_regex_buf
));
489 void regular_expression::copy(const regular_expression
& x
)
491 m_pattern
= x
.m_pattern
;
493 m_errmsg
= x
.m_errmsg
;
495 if (!m_pattern
.empty() && m_errmsg
.empty()) {
496 // There is no POSIX compiled-regex-copy command.
498 throw std::runtime_error(strprintf(
499 "Unable to recompile regular expression \"%s\": %s",
500 m_pattern
.c_str(), m_errmsg
.c_str()));
504 bool regular_expression::compile(const char * pattern
, int flags
)
512 bool regular_expression::compile()
514 int errcode
= regcomp(&m_regex_buf
, m_pattern
.c_str(), m_flags
);
517 regerror(errcode
, &m_regex_buf
, errmsg
, sizeof(errmsg
));
523 const char * errmsg
= check_regex(m_pattern
.c_str());
534 #ifndef HAVE_STRTOULL
535 // Replacement for missing strtoull() (Linux with libc < 6, MSVC)
536 // Functionality reduced to requirements of smartd and split_selective_arg().
538 uint64_t strtoull(const char * p
, char * * endp
, int base
)
540 uint64_t result
, maxres
;
546 if (p
[i
] == 'x' || p
[i
] == 'X') {
558 maxres
= ~(uint64_t)0 / (unsigned)base
;
561 if ('0' <= c
&& c
<= '9')
563 else if ('A' <= c
&& c
<= 'Z')
564 digit
= c
- 'A' + 10;
565 else if ('a' <= c
&& c
<= 'z')
566 digit
= c
- 'a' + 10;
569 if (digit
>= (unsigned)base
)
571 if (!( result
< maxres
572 || (result
== maxres
&& digit
<= ~(uint64_t)0 % (unsigned)base
))) {
573 result
= ~(uint64_t)0; errno
= ERANGE
; // return on overflow
576 result
= result
* (unsigned)base
+ digit
;
580 *endp
= (char *)p
+ i
- 1;
583 #endif // HAVE_STRTOLL
585 // Splits an argument to the -t option that is assumed to be of the form
586 // "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex)
587 // are allowed). The first long long int is assigned to *start and the second
588 // to *stop. Returns zero if successful and non-zero otherwise.
589 int split_selective_arg(char *s
, uint64_t *start
,
590 uint64_t *stop
, int *mode
)
593 if (!(s
= strchr(s
, ',')))
596 if (!isdigit((int)(*++s
))) {
598 if (!strncmp(s
, "redo", 4))
600 else if (!strncmp(s
, "next", 4))
602 else if (!strncmp(s
, "cont", 4))
615 // Last argument to strtoull (the base) is 0 meaning that decimal is assumed
616 // unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used.
617 *start
= strtoull(s
, &tailptr
, 0);
620 if (!(!errno
&& (add
|| *s
== '-')))
622 if (!strcmp(s
, "-max")) {
623 *stop
= ~(uint64_t)0; // replaced by max LBA later
629 *stop
= strtoull(s
+1, &tailptr
, 0);
630 if (errno
|| *tailptr
!= '\0')
635 *stop
+= *start
; // -t select,N+M => -t select,N,(N+M-1)
646 // Helps debugging. If the second argument is non-negative, then
647 // decrement bytes by that amount. Else decrement bytes by (one plus)
648 // length of null terminated string.
649 void *FreeNonZero(void *address
, int size
, int /*line*/, const char* /*file*/){
652 bytes
-=1+strlen((char*)address
);
660 // A custom version of strdup() that keeps track of how much memory is
661 // being allocated. If mustexist is set, it also throws an error if we
662 // try to duplicate a NULL string.
663 char *CustomStrDup(const char *ptr
, int mustexist
, int /*whatline*/, const char* /*file*/){
666 // report error if ptr is NULL and mustexist is set
669 throw std::runtime_error("Internal error in CustomStrDup()");
674 // make a copy of the string...
678 throw std::bad_alloc();
680 // and track memory usage
681 bytes
+=1+strlen(ptr
);
686 #endif // OLD_INTERFACE
689 >>>>>>> 3d8ad6fa4529eb02ae1391a1e937bf57aad3fb74
690 // Returns true if region of memory contains non-zero entries
691 bool nonempty(const void * data
, int size
)
693 for (int i
= 0; i
< size
; i
++)
694 if (((const unsigned char *)data
)[i
])
699 // Copy not null terminated char array to null terminated string.
700 // Replace non-ascii characters. Remove leading and trailing blanks.
701 const char * format_char_array(char * str
, int strsize
, const char * chr
, int chrsize
)
704 while (b
< chrsize
&& chr
[b
] == ' ')
707 while (b
+n
< chrsize
&& chr
[b
+n
])
709 while (n
> 0 && chr
[b
+n
-1] == ' ')
715 for (int i
= 0; i
< n
; i
++) {
717 str
[i
] = (' ' <= c
&& c
<= '~' ? c
: '?');
724 // Format integer with thousands separator
725 const char * format_with_thousands_sep(char * str
, int strsize
, uint64_t val
,
726 const char * thousands_sep
/* = 0 */)
728 if (!thousands_sep
) {
731 setlocale(LC_ALL
, "");
732 const struct lconv
* currentlocale
= localeconv();
733 if (*(currentlocale
->thousands_sep
))
734 thousands_sep
= currentlocale
->thousands_sep
;
739 snprintf(num
, sizeof(num
), "%" PRIu64
, val
);
740 int numlen
= strlen(num
);
745 while (i
< numlen
&& (numlen
- i
) % 3 != 0 && j
< strsize
-1);
748 while (i
< numlen
&& j
< strsize
-1) {
749 j
+= snprintf(str
+j
, strsize
-j
, "%s%.3s", thousands_sep
, num
+i
);
756 // Format capacity with SI prefixes
757 const char * format_capacity(char * str
, int strsize
, uint64_t val
,
758 const char * decimal_point
/* = 0 */)
760 if (!decimal_point
) {
763 setlocale(LC_ALL
, "");
764 const struct lconv
* currentlocale
= localeconv();
765 if (*(currentlocale
->decimal_point
))
766 decimal_point
= currentlocale
->decimal_point
;
770 const unsigned factor
= 1000; // 1024 for KiB,MiB,...
771 static const char prefixes
[] = " KMGTP";
773 // Find d with val in [d, d*factor)
776 for (uint64_t d2
= d
* factor
; val
>= d2
; d2
*= factor
) {
778 if (++i
>= sizeof(prefixes
)-2)
783 uint64_t n
= val
/ d
;
785 snprintf(str
, strsize
, "%u B", (unsigned)n
);
786 else if (n
>= 100) // "123 xB"
787 snprintf(str
, strsize
, "%" PRIu64
" %cB", n
, prefixes
[i
]);
788 else if (n
>= 10) // "12.3 xB"
789 snprintf(str
, strsize
, "%" PRIu64
"%s%u %cB", n
, decimal_point
,
790 (unsigned)(((val
% d
) * 10) / d
), prefixes
[i
]);
792 snprintf(str
, strsize
, "%" PRIu64
"%s%02u %cB", n
, decimal_point
,
793 (unsigned)(((val
% d
) * 100) / d
), prefixes
[i
]);
798 // return (v)sprintf() formatted std::string
800 std::string
vstrprintf(const char * fmt
, va_list ap
)
803 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
804 buf
[sizeof(buf
)-1] = 0;
808 std::string
strprintf(const char * fmt
, ...)
810 va_list ap
; va_start(ap
, fmt
);
811 std::string str
= vstrprintf(fmt
, ap
);
817 #ifndef HAVE_WORKING_SNPRINTF
818 // Some versions of (v)snprintf() don't append null char (MSVCRT.DLL),
819 // and/or return -1 on output truncation (glibc <= 2.0.6).
820 // Below are sane replacements substituted by #define in utility.h.
823 #if defined(_WIN32) && defined(_MSC_VER)
824 #define vsnprintf _vsnprintf
827 int safe_vsnprintf(char *buf
, int size
, const char *fmt
, va_list ap
)
832 i
= vsnprintf(buf
, size
, fmt
, ap
);
833 if (0 <= i
&& i
< size
)
836 return strlen(buf
); // Note: cannot detect for overflow, not necessary here.
839 int safe_snprintf(char *buf
, int size
, const char *fmt
, ...)
843 i
= safe_vsnprintf(buf
, size
, fmt
, ap
);
848 #else // HAVE_WORKING_SNPRINTF
850 static void check_snprintf()
852 char buf
[] = "ABCDEFGHI";
853 int n1
= snprintf(buf
, 8, "123456789");
854 int n2
= snprintf(buf
, 0, "X");
855 if (!(!strcmp(buf
, "1234567") && n1
== 9 && n2
== 1))
856 throw std::logic_error("Function snprintf() does not conform to C99,\n"
857 "please contact " PACKAGE_BUGREPORT
);
860 #endif // HAVE_WORKING_SNPRINTF
862 // Runtime check of ./configure result, throws on error.
866 #ifdef HAVE_WORKING_SNPRINTF