18#define __STDC_FORMAT_MACROS 1
38#include "svnversion.h"
45#ifndef USE_CLOCK_MONOTONIC
50#define USE_CLOCK_MONOTONIC 1
54#define USE_CLOCK_MONOTONIC 0
62 "Direct-access (disk)",
63 "Sequential-access (tape)",
66 "Write-once (optical disk)",
69 "Optical memory (optical disk)",
72 "Graphic arts pre-press (10)",
73 "Graphic arts pre-press (11)",
76 "Reduced block command (simplified disk)",
77 "Optical card reader/writer"
82#define BUILD_INFO "(local build)"
91#ifndef SMARTMONTOOLS_RELEASE_DATE
95#ifdef SMARTMONTOOLS_SVN_REV
96 SMARTMONTOOLS_SVN_DATE
" r" SMARTMONTOOLS_SVN_REV
98 "(build date " __DATE__
")"
101 prog_name,
smi()->get_os_version_str().c_str()
106 info +=
"Copyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org\n";
112 info +=
" comes with ABSOLUTELY NO WARRANTY. This is free\n"
113 "software, and you are welcome to redistribute it under\n"
114 "the terms of the GNU General Public License; either\n"
115 "version 2, or (at your option) any later version.\n"
116 "See https://www.gnu.org for further details.\n"
118#ifndef SMARTMONTOOLS_RELEASE_DATE
119 "smartmontools pre-release " PACKAGE_VERSION
"\n"
121 "smartmontools release " PACKAGE_VERSION
122 " dated " SMARTMONTOOLS_RELEASE_DATE
" at " SMARTMONTOOLS_RELEASE_TIME
"\n"
124#ifdef SMARTMONTOOLS_SVN_REV
125 "smartmontools SVN rev " SMARTMONTOOLS_SVN_REV
126 " dated " SMARTMONTOOLS_SVN_DATE
" at " SMARTMONTOOLS_SVN_TIME
"\n"
128 "smartmontools SVN rev is unknown\n"
130 "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST
"\n"
131 "smartmontools build with: "
134#define N2S(s) N2S_(s)
135#if __cplusplus == 202002
137#elif __cplusplus == 201703
139#elif __cplusplus == 201402
141#elif __cplusplus == 201103
144 "C++(" N2S(__cplusplus)
")"
149#if defined(__GNUC__) && defined(__VERSION__)
152#ifdef __MINGW64_VERSION_STR
153 ", MinGW-w64 " __MINGW64_VERSION_STR
156 "smartmontools configure arguments:"
157#ifdef SOURCE_DATE_EPOCH
158 " [hidden in reproducible builds]\n"
159 "reproducible build SOURCE_DATE_EPOCH: "
162#ifdef SOURCE_DATE_EPOCH
163 char ts[32];
struct tm tmbuf;
164 strftime(ts,
sizeof(ts),
"%Y-%m-%d %H:%M:%S",
time_to_tm_local(&tmbuf, SOURCE_DATE_EPOCH));
165 info +=
strprintf(
"%u (%s)", (
unsigned)SOURCE_DATE_EPOCH, ts);
167 info += (
sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
168 SMARTMONTOOLS_CONFIGURE_ARGS :
" [no arguments given]");
177#if defined (__SVR4) && defined (__sun)
178static const char *TIMEZONE_FILE =
"/etc/TIMEZONE";
180static char *ReadSiteDefaultTimezone(){
186 fp = fopen(TIMEZONE_FILE,
"r");
187 if(fp == NULL)
return NULL;
188 while(fgets(buf,
sizeof(buf), fp)) {
189 if (strncmp(buf,
"TZ=", 3))
192 if (buf[n] ==
'\n') buf[n] = 0;
214 putenv((
char *)
"TZ=GMT");
216 putenv((
char *)
"TZ");
220 const char * tz = getenv(
"TZ");
237#elif defined (__SVR4) && defined (__sun)
244 enum tzstate { NOT_CALLED_YET, USER_TIMEZONE, TRACK_TIMEZONE };
245 static enum tzstate state = NOT_CALLED_YET;
247 static struct stat prev_stat;
248 static char *prev_tz;
249 struct stat curr_stat;
252 if(state == NOT_CALLED_YET) {
254 state = USER_TIMEZONE;
256 state = TRACK_TIMEZONE;
257 if(stat(TIMEZONE_FILE, &prev_stat)) {
258 state = USER_TIMEZONE;
260 prev_tz = ReadSiteDefaultTimezone();
261 if(prev_tz) putenv(prev_tz);
265 }
else if(state == TRACK_TIMEZONE) {
266 if(stat(TIMEZONE_FILE, &curr_stat) == 0
267 && (curr_stat.st_ctime != prev_stat.st_ctime
268 || curr_stat.st_mtime != prev_stat.st_mtime)) {
270 curr_tz = ReadSiteDefaultTimezone();
273 if(prev_tz) free(prev_tz);
274 prev_tz = curr_tz; prev_stat = curr_stat;
289static char * fixtzname(
char * dest,
int destsize,
const char * src)
292 while (src[i] && j < destsize-1) {
293 int i2 = (
const char *)_mbsinc((
const unsigned char *)src+i) - src;
297 if (
'A' <= src[i] && src[i] <=
'Z')
327 if (!localtime_r(&t, tp))
328 throw std::runtime_error(
"localtime_r() failed");
332 if (!localtime_s(&t, tp))
333 throw std::runtime_error(
"localtime_s() failed");
337 if (_localtime64_s(tp, &t64))
338 throw std::runtime_error(
"_localtime64_s() failed");
361 if (!asctime_r(tmval, datebuffer))
362 throw std::runtime_error(
"asctime_r() failed");
365 if (asctime_s(datebuffer,
sizeof(datebuffer), tmval))
366 throw std::runtime_error(
"asctime_s() failed");
370 int lenm1 = strlen(datebuffer) - 1;
371 datebuffer[lenm1>=0?lenm1:0]=
'\0';
373#if defined(_WIN32) && defined(_MSC_VER)
375 #define tzname _tzname
379 const char * timezonename;
380 if (tmval->tm_isdst==0)
382 timezonename=tzname[0];
383 else if (tmval->tm_isdst>0)
385 timezonename=tzname[1];
393 char tzfixbuf[6+1] =
"";
395 timezonename=fixtzname(tzfixbuf,
sizeof(tzfixbuf), timezonename);
410 const char *errormessage=strerror(errno);
414 if (message && *message)
415 pout(
"%s: %s\n",message, errormessage);
417 pout(
"%s\n",errormessage);
419 else if (message && *message)
420 pout(
"%s\n",message);
445 for (
int i = 0; (c = pattern[i]); i++) {
455 if (pattern[++i] ==
'^')
459 while ((c = pattern[i]) && c !=
']')
469 else if (c ==
')' && --level < 0)
470 return "Unmatched ')'";
474 if ( (c ==
'|' && ( i == 0 || !(c1 = pattern[i+1])
475 || c1 ==
'|' || c1 ==
')' || c1 ==
'$'))
476 || ((c ==
'(' || c ==
'^') && pattern[i+1] ==
'|') )
477 return "Empty '|' subexpression";
480 return (
const char *)0;
485#ifndef WITH_CXX11_REGEX
498: m_pattern(x.m_pattern),
528 "Unable to recompile regular expression \"%s\": %s",
540 "error in regular expression \"%s\": %s",
546#ifndef WITH_CXX11_REGEX
555#ifdef WITH_CXX11_REGEX
557 m_regex.assign(
m_pattern, std::regex_constants::extended);
559 catch (std::regex_error & ex) {
568 regerror(errcode, &
m_regex_buf, errmsg,
sizeof(errmsg));
578#ifdef WITH_CXX11_REGEX
579 m_regex = std::regex();
592#ifdef WITH_CXX11_REGEX
593 return std::regex_match(str, m_regex);
597 && range.rm_so == 0 && range.rm_eo == (
int)strlen(str));
603#ifdef WITH_CXX11_REGEX
605 if (!std::regex_search(str, m, m_regex))
607 unsigned sz = m.size();
608 for (
unsigned i = 0; i < nmatch; i++) {
609 if (i < sz && *m[i].first) {
610 pmatch[i].rm_so = m[i].first - str;
611 pmatch[i].rm_eo = m[i].second - str;
614 pmatch[i].rm_so = pmatch[i].rm_eo = -1;
619 return !regexec(&
m_regex_buf, str, nmatch, pmatch, 0);
628 uint64_t *stop,
int *mode)
631 if (!(
s = strchr(
s,
',')))
634 if (!isdigit((
int)(*++
s))) {
636 if (!strncmp(
s,
"redo", 4))
638 else if (!strncmp(
s,
"next", 4))
640 else if (!strncmp(
s,
"cont", 4))
655 *start = strtoull(
s, &tailptr, 0);
658 if (!(!errno && (add || *
s ==
'-')))
660 if (!strcmp(
s,
"-max")) {
661 *stop = ~(uint64_t)0;
667 *stop = strtoull(
s+1, &tailptr, 0);
668 if (errno || *tailptr !=
'\0')
681 for (
int i = 0; i <
size; i++)
682 if (((
const unsigned char *)
data)[i])
692 while (
b < chrsize && chr[
b] ==
' ')
695 while (
b+n < chrsize && chr[
b+n])
697 while (n > 0 && chr[
b+n-1] ==
' ')
703 for (
int i = 0; i < n; i++) {
705 str[i] = (
' ' <= c && c <=
'~' ? c :
'?');
714 const char * thousands_sep )
716 if (!thousands_sep) {
719 setlocale(LC_ALL,
"");
720 const struct lconv * currentlocale = localeconv();
721 if (*(currentlocale->thousands_sep))
722 thousands_sep = currentlocale->thousands_sep;
727 snprintf(num,
sizeof(num),
"%" PRIu64, val);
728 int numlen = strlen(num);
733 while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1);
736 while (i < numlen && j < strsize-1) {
737 j += snprintf(str+j, strsize-j,
"%s%.3s", thousands_sep, num+i);
746 const char * decimal_point )
748 if (!decimal_point) {
751 setlocale(LC_ALL,
"");
752 const struct lconv * currentlocale = localeconv();
753 if (*(currentlocale->decimal_point))
754 decimal_point = currentlocale->decimal_point;
758 const unsigned factor = 1000;
759 static const char prefixes[] =
" KMGTP";
764 for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) {
766 if (++i >=
sizeof(prefixes)-2)
771 uint64_t n = val / d;
773 snprintf(str, strsize,
"%u B", (
unsigned)n);
775 snprintf(str, strsize,
"%" PRIu64
" %cB", n, prefixes[i]);
777 snprintf(str, strsize,
"%" PRIu64
"%s%u %cB", n, decimal_point,
778 (
unsigned)(((val % d) * 10) / d), prefixes[i]);
780 snprintf(str, strsize,
"%" PRIu64
"%s%02u %cB", n, decimal_point,
781 (
unsigned)(((val % d) * 100) / d), prefixes[i]);
792 buf[
sizeof(buf)-1] = 0;
804#if defined(HAVE___INT128)
808static int snprint_uint128(
char * str,
int strsize,
unsigned __int128 value)
813 if (value <= 0xffffffffffffffffULL) {
815 return snprintf(str, (
size_t)strsize,
"%" PRIu64, (uint64_t)value);
819 const uint64_t e19 = 10000000000000000000ULL;
820 int len1 = snprint_uint128(str, strsize, value / e19);
825 int len2 = snprintf(str + (len1 < strsize ? len1 : strsize - 1),
826 (
size_t)(len1 < strsize ? strsize - len1 : 1),
827 "%019" PRIu64, (uint64_t)(value % e19) );
835const char *
uint128_hilo_to_str(
char * str,
int strsize, uint64_t value_hi, uint64_t value_lo)
837 snprint_uint128(str, strsize, ((
unsigned __int128)value_hi << 64) | value_lo);
841#elif defined(HAVE_LONG_DOUBLE_WIDER_PRINTF)
844const char *
uint128_hilo_to_str(
char * str,
int strsize, uint64_t value_hi, uint64_t value_lo)
846 snprintf(str, strsize,
"%.0Lf", value_hi * (0xffffffffffffffffULL + 1.0L) + value_lo);
855 snprintf(str, strsize,
"%.0f", value_hi * (0xffffffffffffffffULL + 1.0) + value_lo);
864#if USE_CLOCK_MONOTONIC
866 if (clock_gettime(CLOCK_MONOTONIC, &ts))
868 return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
870 return std::chrono::duration_cast<std::chrono::microseconds>(
871 std::chrono::high_resolution_clock::now().time_since_epoch()
881 unsigned char c[
sizeof(int) == 4 ? 8 : -1];
883 } x = {{1, 2, 3, 4, 5, 6, 7, 8}};
884 const uint64_t le = 0x0807060504030201ULL;
885 const uint64_t be = 0x0102030405060708ULL;
894 throw std::logic_error(
"CPU endianness does not match compile time test");
897#if defined(__GNUC__) && (__GNUC__ >= 7)
906 char buf[] =
"ABCDEFGHI";
907 int n1 = snprintf(buf, 8,
"123456789");
908 int n2 = snprintf(buf, 0,
"X");
909 if (!(!strcmp(buf,
"1234567") && n1 == 9 && n2 == 1))
910 throw std::logic_error(
"Function snprintf() does not conform to C99");
Wrapper class for POSIX regex(3) or std::regex Supports copy & assignment and is compatible with STL ...
bool full_match(const char *str) const
Return true if full string matches pattern.
regular_expression & operator=(const regular_expression &x)
void copy_buf(const regular_expression &x)
bool execute(const char *str, unsigned nmatch, match_range *pmatch) const
Return true if substring matches pattern, fill match_range array.
smart_interface * smi()
Global access to the (usually singleton) smart_interface.
static uint64_t sg_get_unaligned_le64(const void *p)
static uint32_t sg_get_unaligned_le32(const void *p)
static uint64_t sg_get_unaligned_be64(const void *p)
static uint16_t sg_get_unaligned_be16(const void *p)
static uint16_t sg_get_unaligned_le16(const void *p)
static uint32_t sg_get_unaligned_be32(const void *p)
const char const char * fmt
const char const char va_list ap
vsnprintf(buf, sizeof(buf), fmt, ap)
void pout(const char *fmt,...)
void FixGlibcTimeZoneBug()
const char * format_char_array(char *str, int strsize, const char *chr, int chrsize)
std::string format_version_info(const char *prog_name, int lines)
void dateandtimezoneepoch(char(&buffer)[DATEANDEPOCHLEN], time_t tval)
long long get_timer_usec()
Get microseconds since some unspecified starting point.
const char * packet_types[]
const char * format_capacity(char *str, int strsize, uint64_t val, const char *decimal_point)
const char * format_with_thousands_sep(char *str, int strsize, uint64_t val, const char *thousands_sep)
void syserror(const char *message)
std::string strprintf(const char *fmt,...)
const char * utility_cpp_cvsid
static const char * check_regex(const char *pattern)
bool nonempty(const void *data, int size)
static void check_endianness()
int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode)
const char * uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo)
const char * packetdevicetype(int type)
struct tm * time_to_tm_local(struct tm *tp, time_t t)
static void check_snprintf()
std::string std::string vstrprintf(const char *fmt, va_list ap)
std::string strprintf(const char *fmt,...) __attribute_format_printf(1
bool nonempty(const void *data, int size)
#define __attribute_format_printf(x, y)