smartmontools  SVN Rev 4048
Utility to control and monitor storage systems with "S.M.A.R.T."
utility.cpp
Go to the documentation of this file.
1 /*
2  * utility.cpp
3  *
4  * Home page of code is: http://smartmontools.sourceforge.net
5  *
6  * Copyright (C) 2002-12 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7  * Copyright (C) 2008-15 Christian Franke <smartmontools-support@lists.sourceforge.net>
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, see <http://www.gnu.org/licenses/>.
17  *
18  * This code was originally developed as a Senior Thesis by Michael Cornwell
19  * at the Concurrent Systems Laboratory (now part of the Storage Systems
20  * Research Center), Jack Baskin School of Engineering, University of
21  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
22  *
23  */
24 
25 // THIS FILE IS INTENDED FOR UTILITY ROUTINES THAT ARE APPLICABLE TO
26 // BOTH SCSI AND ATA DEVICES, AND THAT MAY BE USED IN SMARTD,
27 // SMARTCTL, OR BOTH.
28 
29 #include "config.h"
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #include <sys/stat.h>
39 #ifdef HAVE_LOCALE_H
40 #include <locale.h>
41 #endif
42 #ifdef _WIN32
43 #include <mbstring.h> // _mbsinc()
44 #endif
45 
46 #include <stdexcept>
47 
48 #include "svnversion.h"
49 #include "int64.h"
50 #include "utility.h"
51 
52 #include "atacmds.h"
53 #include "dev_interface.h"
54 
55 const char * utility_cpp_cvsid = "$Id: utility.cpp 4031 2015-01-01 10:47:48Z chrfranke $"
57 
58 const char * packet_types[] = {
59  "Direct-access (disk)",
60  "Sequential-access (tape)",
61  "Printer",
62  "Processor",
63  "Write-once (optical disk)",
64  "CD/DVD",
65  "Scanner",
66  "Optical memory (optical disk)",
67  "Medium changer",
68  "Communications",
69  "Graphic arts pre-press (10)",
70  "Graphic arts pre-press (11)",
71  "Array controller",
72  "Enclosure services",
73  "Reduced block command (simplified disk)",
74  "Optical card reader/writer"
75 };
76 
77 // BUILD_INFO can be provided by package maintainers
78 #ifndef BUILD_INFO
79 #define BUILD_INFO "(local build)"
80 #endif
81 
82 // Make version information string
83 std::string format_version_info(const char * prog_name, bool full /*= false*/)
84 {
85  std::string info = strprintf(
86  "%s " PACKAGE_VERSION " "
87 #ifdef SMARTMONTOOLS_SVN_REV
88  SMARTMONTOOLS_SVN_DATE " r" SMARTMONTOOLS_SVN_REV
89 #else
90  "(build date " __DATE__ ")" // checkout without expansion of Id keywords
91 #endif
92  " [%s] " BUILD_INFO "\n"
93  "Copyright (C) 2002-15, Bruce Allen, Christian Franke, www.smartmontools.org\n",
94  prog_name, smi()->get_os_version_str().c_str()
95  );
96  if (!full)
97  return info;
98 
99  info += strprintf(
100  "\n"
101  "%s comes with ABSOLUTELY NO WARRANTY. This is free\n"
102  "software, and you are welcome to redistribute it under\n"
103  "the terms of the GNU General Public License; either\n"
104  "version 2, or (at your option) any later version.\n"
105  "See http://www.gnu.org for further details.\n"
106  "\n",
107  prog_name
108  );
109  info +=
110  "smartmontools release " PACKAGE_VERSION
111  " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"
112 #ifdef SMARTMONTOOLS_SVN_REV
113  "smartmontools SVN rev " SMARTMONTOOLS_SVN_REV
114  " dated " SMARTMONTOOLS_SVN_DATE " at " SMARTMONTOOLS_SVN_TIME "\n"
115 #else
116  "smartmontools SVN rev is unknown\n"
117 #endif
118  "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"
119 #if defined(__GNUC__) && defined(__VERSION__) // works also with CLang
120  "smartmontools build with: GCC " __VERSION__ "\n"
121 #endif
122  "smartmontools configure arguments: "
123  ;
124  info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
125  SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]");
126  info += '\n';
127 
128  return info;
129 }
130 
131 // Solaris only: Get site-default timezone. This is called from
132 // UpdateTimezone() when TZ environment variable is unset at startup.
133 #if defined (__SVR4) && defined (__sun)
134 static const char *TIMEZONE_FILE = "/etc/TIMEZONE";
135 
136 static char *ReadSiteDefaultTimezone(){
137  FILE *fp;
138  char buf[512], *tz;
139  int n;
140 
141  tz = NULL;
142  fp = fopen(TIMEZONE_FILE, "r");
143  if(fp == NULL) return NULL;
144  while(fgets(buf, sizeof(buf), fp)) {
145  if (strncmp(buf, "TZ=", 3)) // searches last "TZ=" line
146  continue;
147  n = strlen(buf) - 1;
148  if (buf[n] == '\n') buf[n] = 0;
149  if (tz) free(tz);
150  tz = strdup(buf);
151  }
152  fclose(fp);
153  return tz;
154 }
155 #endif
156 
157 // Make sure that this executable is aware if the user has changed the
158 // time-zone since the last time we polled devices. The cannonical
159 // example is a user who starts smartd on a laptop, then flies across
160 // time-zones with a laptop, and then changes the timezone, WITHOUT
161 // restarting smartd. This is a work-around for a bug in
162 // GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and
163 // thanks to Ian Redfern for posting a workaround.
164 
165 // Please refer to the smartd manual page, in the section labeled LOG
166 // TIMESTAMP TIMEZONE.
168 #if __GLIBC__
169  if (!getenv("TZ")) {
170  putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
171  tzset();
172  putenv((char *)"TZ");
173  tzset();
174  }
175 #elif _WIN32
176  if (!getenv("TZ")) {
177  putenv("TZ=GMT");
178  tzset();
179  putenv("TZ="); // empty value removes TZ, putenv("TZ") does nothing
180  tzset();
181  }
182 #elif defined (__SVR4) && defined (__sun)
183  // In Solaris, putenv("TZ=") sets null string and invalid timezone.
184  // putenv("TZ") does nothing. With invalid TZ, tzset() do as if
185  // TZ=GMT. With TZ unset, /etc/TIMEZONE will be read only _once_ at
186  // first tzset() call. Conclusion: Unlike glibc, dynamic
187  // configuration of timezone can be done only by changing actual
188  // value of TZ environment value.
189  enum tzstate { NOT_CALLED_YET, USER_TIMEZONE, TRACK_TIMEZONE };
190  static enum tzstate state = NOT_CALLED_YET;
191 
192  static struct stat prev_stat;
193  static char *prev_tz;
194  struct stat curr_stat;
195  char *curr_tz;
196 
197  if(state == NOT_CALLED_YET) {
198  if(getenv("TZ")) {
199  state = USER_TIMEZONE; // use supplied timezone
200  } else {
201  state = TRACK_TIMEZONE;
202  if(stat(TIMEZONE_FILE, &prev_stat)) {
203  state = USER_TIMEZONE; // no TZ, no timezone file; use GMT forever
204  } else {
205  prev_tz = ReadSiteDefaultTimezone(); // track timezone file change
206  if(prev_tz) putenv(prev_tz);
207  }
208  }
209  tzset();
210  } else if(state == TRACK_TIMEZONE) {
211  if(stat(TIMEZONE_FILE, &curr_stat) == 0
212  && (curr_stat.st_ctime != prev_stat.st_ctime
213  || curr_stat.st_mtime != prev_stat.st_mtime)) {
214  // timezone file changed
215  curr_tz = ReadSiteDefaultTimezone();
216  if(curr_tz) {
217  putenv(curr_tz);
218  if(prev_tz) free(prev_tz);
219  prev_tz = curr_tz; prev_stat = curr_stat;
220  }
221  }
222  tzset();
223  }
224 #endif
225  // OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED. PLEASE TRY TO
226  // KEEP THEM INDEPENDENT.
227  return;
228 }
229 
230 #ifdef _WIN32
231 // Fix strings in tzname[] to avoid long names with non-ascii characters.
232 // If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
233 // national language timezone names returned by GetTimezoneInformation().
234 static char * fixtzname(char * dest, int destsize, const char * src)
235 {
236  int i = 0, j = 0;
237  while (src[i] && j < destsize-1) {
238  int i2 = (const char *)_mbsinc((const unsigned char *)src+i) - src;
239  if (i2 > i+1)
240  i = i2; // Ignore multibyte chars
241  else {
242  if ('A' <= src[i] && src[i] <= 'Z')
243  dest[j++] = src[i]; // "Pacific Standard Time" => "PST"
244  i++;
245  }
246  }
247  if (j < 2)
248  j = 0;
249  dest[j] = 0;
250  return dest;
251 }
252 #endif // _WIN32
253 
254 // This value follows the peripheral device type value as defined in
255 // SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
256 // the ATA standard for packet devices to define the device type.
257 const char *packetdevicetype(int type){
258  if (type<0x10)
259  return packet_types[type];
260 
261  if (type<0x20)
262  return "Reserved";
263 
264  return "Unknown";
265 }
266 
267 // Runtime check of byte ordering, throws if different from isbigendian().
268 static void check_endianness()
269 {
270  union {
271  // Force compile error if int type is not 32bit.
272  unsigned char c[sizeof(unsigned) == 4 ? 4 : -1];
273  unsigned i;
274  } x = {{1,2,3,4}};
275 
276  int big = -1;
277  switch (x.i) {
278  case 0x01020304: big = 1; break;
279  case 0x04030201: big = 0; break;
280  }
281 
282  if (big != (isbigendian() ? 1 : 0))
283  throw std::logic_error("CPU endianness does not match compile time test");
284 }
285 
286 // Utility function prints date and time and timezone into a character
287 // buffer of length>=64. All the fuss is needed to get the right
288 // timezone info (sigh).
289 void dateandtimezoneepoch(char *buffer, time_t tval){
290  struct tm *tmval;
291  const char *timezonename;
292  char datebuffer[DATEANDEPOCHLEN];
293  int lenm1;
294 #ifdef _WIN32
295  char tzfixbuf[6+1];
296 #endif
297 
299 
300  // Get the time structure. We need this to determine if we are in
301  // daylight savings time or not.
302  tmval=localtime(&tval);
303 
304  // Convert to an ASCII string, put in datebuffer
305  // same as: asctime_r(tmval, datebuffer);
306  strncpy(datebuffer, asctime(tmval), DATEANDEPOCHLEN);
307  datebuffer[DATEANDEPOCHLEN-1]='\0';
308 
309  // Remove newline
310  lenm1=strlen(datebuffer)-1;
311  datebuffer[lenm1>=0?lenm1:0]='\0';
312 
313  // correct timezone name
314  if (tmval->tm_isdst==0)
315  // standard time zone
316  timezonename=tzname[0];
317  else if (tmval->tm_isdst>0)
318  // daylight savings in effect
319  timezonename=tzname[1];
320  else
321  // unable to determine if daylight savings in effect
322  timezonename="";
323 
324 #ifdef _WIN32
325  // Fix long non-ascii timezone names
326  if (!getenv("TZ"))
327  timezonename=fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename);
328 #endif
329 
330  // Finally put the information into the buffer as needed.
331  snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename);
332 
333  return;
334 }
335 
336 // Date and timezone gets printed into string pointed to by buffer
338 
339  // Get the epoch (time in seconds since Jan 1 1970)
340  time_t tval=time(NULL);
341 
342  dateandtimezoneepoch(buffer, tval);
343  return;
344 }
345 
346 // A replacement for perror() that sends output to our choice of
347 // printing. If errno not set then just print message.
348 void syserror(const char *message){
349 
350  if (errno) {
351  // Get the correct system error message:
352  const char *errormessage=strerror(errno);
353 
354  // Check that caller has handed a sensible string, and provide
355  // appropriate output. See perrror(3) man page to understand better.
356  if (message && *message)
357  pout("%s: %s\n",message, errormessage);
358  else
359  pout("%s\n",errormessage);
360  }
361  else if (message && *message)
362  pout("%s\n",message);
363 
364  return;
365 }
366 
367 // Check regular expression for non-portable features.
368 //
369 // POSIX extended regular expressions interpret unmatched ')' ordinary:
370 // "The close-parenthesis shall be considered special in this context
371 // only if matched with a preceding open-parenthesis."
372 //
373 // GNU libc and BSD libc support unmatched ')', Cygwin reports an error.
374 //
375 // POSIX extended regular expressions do not define empty subexpressions:
376 // "A vertical-line appearing first or last in an ERE, or immediately following
377 // a vertical-line or a left-parenthesis, or immediately preceding a
378 // right-parenthesis, produces undefined results."
379 //
380 // GNU libc and Cygwin support empty subexpressions, BSD libc reports an error.
381 //
382 static const char * check_regex(const char * pattern)
383 {
384  int level = 0;
385  char c;
386 
387  for (int i = 0; (c = pattern[i]); i++) {
388  // Skip "\x"
389  if (c == '\\') {
390  if (!pattern[++i])
391  break;
392  continue;
393  }
394 
395  // Skip "[...]"
396  if (c == '[') {
397  if (pattern[++i] == '^')
398  i++;
399  if (!pattern[i++])
400  break;
401  while ((c = pattern[i]) && c != ']')
402  i++;
403  if (!c)
404  break;
405  continue;
406  }
407 
408  // Check "(...)" nesting
409  if (c == '(')
410  level++;
411  else if (c == ')' && --level < 0)
412  return "Unmatched ')'";
413 
414  // Check for leading/trailing '|' or "||", "|)", "|$", "(|", "^|"
415  char c1;
416  if ( (c == '|' && ( i == 0 || !(c1 = pattern[i+1])
417  || c1 == '|' || c1 == ')' || c1 == '$'))
418  || ((c == '(' || c == '^') && pattern[i+1] == '|') )
419  return "Empty '|' subexpression";
420  }
421 
422  return (const char *)0;
423 }
424 
425 // Wrapper class for regex(3)
426 
428 : m_flags(0)
429 {
430  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
431 }
432 
434  bool throw_on_error /*= true*/)
435 {
436  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
437  if (!compile(pattern, flags) && throw_on_error)
438  throw std::runtime_error(strprintf(
439  "error in regular expression \"%s\": %s",
440  m_pattern.c_str(), m_errmsg.c_str()));
441 }
442 
444 {
445  free_buf();
446 }
447 
449 {
450  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
451  copy(x);
452 }
453 
455 {
456  free_buf();
457  copy(x);
458  return *this;
459 }
460 
462 {
463  if (nonempty(&m_regex_buf, sizeof(m_regex_buf))) {
464  regfree(&m_regex_buf);
465  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
466  }
467 }
468 
470 {
471  m_pattern = x.m_pattern;
472  m_flags = x.m_flags;
473  m_errmsg = x.m_errmsg;
474 
475  if (!m_pattern.empty() && m_errmsg.empty()) {
476  // There is no POSIX compiled-regex-copy command.
477  if (!compile())
478  throw std::runtime_error(strprintf(
479  "Unable to recompile regular expression \"%s\": %s",
480  m_pattern.c_str(), m_errmsg.c_str()));
481  }
482 }
483 
484 bool regular_expression::compile(const char * pattern, int flags)
485 {
486  free_buf();
487  m_pattern = pattern;
488  m_flags = flags;
489  return compile();
490 }
491 
493 {
494  int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), m_flags);
495  if (errcode) {
496  char errmsg[512];
497  regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg));
498  m_errmsg = errmsg;
499  free_buf();
500  return false;
501  }
502 
503  const char * errmsg = check_regex(m_pattern.c_str());
504  if (errmsg) {
505  m_errmsg = errmsg;
506  free_buf();
507  return false;
508  }
509 
510  m_errmsg.clear();
511  return true;
512 }
513 
514 // Splits an argument to the -r option into a name part and an (optional)
515 // positive integer part. s is a pointer to a string containing the
516 // argument. After the call, s will point to the name part and *i the
517 // integer part if there is one or 1 otherwise. Note that the string s may
518 // be changed by this function. Returns zero if successful and non-zero
519 // otherwise.
520 int split_report_arg(char *s, int *i)
521 {
522  if ((s = strchr(s, ','))) {
523  // Looks like there's a name part and an integer part.
524  char *tailptr;
525 
526  *s++ = '\0';
527  if (*s == '0' || !isdigit((int)*s)) // The integer part must be positive
528  return 1;
529  errno = 0;
530  *i = (int) strtol(s, &tailptr, 10);
531  if (errno || *tailptr != '\0')
532  return 1;
533  } else {
534  // There's no integer part.
535  *i = 1;
536  }
537 
538  return 0;
539 }
540 
541 #ifndef HAVE_STRTOULL
542 // Replacement for missing strtoull() (Linux with libc < 6, MSVC)
543 // Functionality reduced to requirements of smartd and split_selective_arg().
544 
545 uint64_t strtoull(const char * p, char * * endp, int base)
546 {
547  uint64_t result, maxres;
548  int i = 0;
549  char c = p[i++];
550 
551  if (!base) {
552  if (c == '0') {
553  if (p[i] == 'x' || p[i] == 'X') {
554  base = 16; i++;
555  }
556  else
557  base = 8;
558  c = p[i++];
559  }
560  else
561  base = 10;
562  }
563 
564  result = 0;
565  maxres = ~(uint64_t)0 / (unsigned)base;
566  for (;;) {
567  unsigned digit;
568  if ('0' <= c && c <= '9')
569  digit = c - '0';
570  else if ('A' <= c && c <= 'Z')
571  digit = c - 'A' + 10;
572  else if ('a' <= c && c <= 'z')
573  digit = c - 'a' + 10;
574  else
575  break;
576  if (digit >= (unsigned)base)
577  break;
578  if (!( result < maxres
579  || (result == maxres && digit <= ~(uint64_t)0 % (unsigned)base))) {
580  result = ~(uint64_t)0; errno = ERANGE; // return on overflow
581  break;
582  }
583  result = result * (unsigned)base + digit;
584  c = p[i++];
585  }
586  if (endp)
587  *endp = (char *)p + i - 1;
588  return result;
589 }
590 #endif // HAVE_STRTOLL
591 
592 // Splits an argument to the -t option that is assumed to be of the form
593 // "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex)
594 // are allowed). The first long long int is assigned to *start and the second
595 // to *stop. Returns zero if successful and non-zero otherwise.
596 int split_selective_arg(char *s, uint64_t *start,
597  uint64_t *stop, int *mode)
598 {
599  char *tailptr;
600  if (!(s = strchr(s, ',')))
601  return 1;
602  bool add = false;
603  if (!isdigit((int)(*++s))) {
604  *start = *stop = 0;
605  if (!strncmp(s, "redo", 4))
606  *mode = SEL_REDO;
607  else if (!strncmp(s, "next", 4))
608  *mode = SEL_NEXT;
609  else if (!strncmp(s, "cont", 4))
610  *mode = SEL_CONT;
611  else
612  return 1;
613  s += 4;
614  if (!*s)
615  return 0;
616  if (*s != '+')
617  return 1;
618  }
619  else {
620  *mode = SEL_RANGE;
621  errno = 0;
622  // Last argument to strtoull (the base) is 0 meaning that decimal is assumed
623  // unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used.
624  *start = strtoull(s, &tailptr, 0);
625  s = tailptr;
626  add = (*s == '+');
627  if (!(!errno && (add || *s == '-')))
628  return 1;
629  if (!strcmp(s, "-max")) {
630  *stop = ~(uint64_t)0; // replaced by max LBA later
631  return 0;
632  }
633  }
634 
635  errno = 0;
636  *stop = strtoull(s+1, &tailptr, 0);
637  if (errno || *tailptr != '\0')
638  return 1;
639  if (add) {
640  if (*stop > 0)
641  (*stop)--;
642  *stop += *start; // -t select,N+M => -t select,N,(N+M-1)
643  }
644  return 0;
645 }
646 
647 #ifdef OLD_INTERFACE
648 
649 int64_t bytes = 0;
650 
651 // Helps debugging. If the second argument is non-negative, then
652 // decrement bytes by that amount. Else decrement bytes by (one plus)
653 // length of null terminated string.
654 void *FreeNonZero(void *address, int size, int /*line*/, const char* /*file*/){
655  if (address) {
656  if (size<0)
657  bytes-=1+strlen((char*)address);
658  else
659  bytes-=size;
660  free(address);
661  }
662  return NULL;
663 }
664 
665 // A custom version of strdup() that keeps track of how much memory is
666 // being allocated. If mustexist is set, it also throws an error if we
667 // try to duplicate a NULL string.
668 char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){
669  char *tmp;
670 
671  // report error if ptr is NULL and mustexist is set
672  if (ptr==NULL){
673  if (mustexist)
674  throw std::runtime_error("Internal error in CustomStrDup()");
675  else
676  return NULL;
677  }
678 
679  // make a copy of the string...
680  tmp=strdup(ptr);
681 
682  if (!tmp)
683  throw std::bad_alloc();
684 
685  // and track memory usage
686  bytes+=1+strlen(ptr);
687 
688  return tmp;
689 }
690 
691 #endif // OLD_INTERFACE
692 
693 
694 // Returns true if region of memory contains non-zero entries
695 bool nonempty(const void * data, int size)
696 {
697  for (int i = 0; i < size; i++)
698  if (((const unsigned char *)data)[i])
699  return true;
700  return false;
701 }
702 
703 // Format integer with thousands separator
704 const char * format_with_thousands_sep(char * str, int strsize, uint64_t val,
705  const char * thousands_sep /* = 0 */)
706 {
707  if (!thousands_sep) {
708  thousands_sep = ",";
709 #ifdef HAVE_LOCALE_H
710  setlocale(LC_ALL, "");
711  const struct lconv * currentlocale = localeconv();
712  if (*(currentlocale->thousands_sep))
713  thousands_sep = currentlocale->thousands_sep;
714 #endif
715  }
716 
717  char num[64];
718  snprintf(num, sizeof(num), "%" PRIu64, val);
719  int numlen = strlen(num);
720 
721  int i = 0, j = 0;
722  do
723  str[j++] = num[i++];
724  while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1);
725  str[j] = 0;
726 
727  while (i < numlen && j < strsize-1) {
728  j += snprintf(str+j, strsize-j, "%s%.3s", thousands_sep, num+i);
729  i += 3;
730  }
731 
732  return str;
733 }
734 
735 // Format capacity with SI prefixes
736 const char * format_capacity(char * str, int strsize, uint64_t val,
737  const char * decimal_point /* = 0 */)
738 {
739  if (!decimal_point) {
740  decimal_point = ".";
741 #ifdef HAVE_LOCALE_H
742  setlocale(LC_ALL, "");
743  const struct lconv * currentlocale = localeconv();
744  if (*(currentlocale->decimal_point))
745  decimal_point = currentlocale->decimal_point;
746 #endif
747  }
748 
749  const unsigned factor = 1000; // 1024 for KiB,MiB,...
750  static const char prefixes[] = " KMGTP";
751 
752  // Find d with val in [d, d*factor)
753  unsigned i = 0;
754  uint64_t d = 1;
755  for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) {
756  d = d2;
757  if (++i >= sizeof(prefixes)-2)
758  break;
759  }
760 
761  // Print 3 digits
762  uint64_t n = val / d;
763  if (i == 0)
764  snprintf(str, strsize, "%u B", (unsigned)n);
765  else if (n >= 100) // "123 xB"
766  snprintf(str, strsize, "%" PRIu64 " %cB", n, prefixes[i]);
767  else if (n >= 10) // "12.3 xB"
768  snprintf(str, strsize, "%" PRIu64 "%s%u %cB", n, decimal_point,
769  (unsigned)(((val % d) * 10) / d), prefixes[i]);
770  else // "1.23 xB"
771  snprintf(str, strsize, "%" PRIu64 "%s%02u %cB", n, decimal_point,
772  (unsigned)(((val % d) * 100) / d), prefixes[i]);
773 
774  return str;
775 }
776 
777 // return (v)sprintf() formatted std::string
778 
779 std::string vstrprintf(const char * fmt, va_list ap)
780 {
781  char buf[512];
782  vsnprintf(buf, sizeof(buf), fmt, ap);
783  buf[sizeof(buf)-1] = 0;
784  return buf;
785 }
786 
787 std::string strprintf(const char * fmt, ...)
788 {
789  va_list ap; va_start(ap, fmt);
790  std::string str = vstrprintf(fmt, ap);
791  va_end(ap);
792  return str;
793 }
794 
795 
796 #ifndef HAVE_WORKING_SNPRINTF
797 // Some versions of (v)snprintf() don't append null char (MSVCRT.DLL),
798 // and/or return -1 on output truncation (glibc <= 2.0.6).
799 // Below are sane replacements substituted by #define in utility.h.
800 
801 #undef vsnprintf
802 #if defined(_WIN32) && defined(_MSC_VER)
803 #define vsnprintf _vsnprintf
804 #endif
805 
806 int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
807 {
808  int i;
809  if (size <= 0)
810  return 0;
811  i = vsnprintf(buf, size, fmt, ap);
812  if (0 <= i && i < size)
813  return i;
814  buf[size-1] = 0;
815  return strlen(buf); // Note: cannot detect for overflow, not necessary here.
816 }
817 
818 int safe_snprintf(char *buf, int size, const char *fmt, ...)
819 {
820  int i; va_list ap;
821  va_start(ap, fmt);
822  i = safe_vsnprintf(buf, size, fmt, ap);
823  va_end(ap);
824  return i;
825 }
826 
827 #else // HAVE_WORKING_SNPRINTF
828 
829 static void check_snprintf()
830 {
831  char buf[] = "ABCDEFGHI";
832  int n1 = snprintf(buf, 8, "123456789");
833  int n2 = snprintf(buf, 0, "X");
834  if (!(!strcmp(buf, "1234567") && n1 == 9 && n2 == 1))
835  throw std::logic_error("Function snprintf() does not conform to C99,\n"
836  "please contact " PACKAGE_BUGREPORT);
837 }
838 
839 #endif // HAVE_WORKING_SNPRINTF
840 
841 // Runtime check of ./configure result, throws on error.
843 {
845 #ifdef HAVE_WORKING_SNPRINTF
846  check_snprintf();
847 #endif
848 }
#define PRIu64
Definition: int64.h:76
regex_t m_regex_buf
Definition: utility.h:284
bool isbigendian()
Definition: utility.h:120
const char * packetdevicetype(int type)
Definition: utility.cpp:257
u16 s[6]
Definition: megaraid.h:97
#define vsnprintf
Definition: utility.h:69
long long bytes
Definition: os_freebsd.cpp:124
u32 size
Definition: megaraid.h:79
const char * utility_cpp_cvsid
Definition: utility.cpp:55
void dateandtimezone(char *buffer)
Definition: utility.cpp:337
smart_interface * smi()
Global access to the (usually singleton) smart_interface.
std::string format_version_info(const char *prog_name, bool full)
Definition: utility.cpp:83
void FixGlibcTimeZoneBug()
Definition: utility.cpp:167
#define BUILD_INFO
Definition: utility.cpp:79
static const char * check_regex(const char *pattern)
Definition: utility.cpp:382
#define snprintf
Definition: utility.h:68
void dateandtimezoneepoch(char *buffer, time_t tval)
Definition: utility.cpp:289
u16 flags
Definition: megaraid.h:93
const char * packet_types[]
Definition: utility.cpp:58
#define INT64_H_CVSID
Definition: int64.h:23
bool nonempty(const void *data, int size)
Definition: utility.cpp:695
ptr_t data
Definition: megaraid.h:94
#define DATEANDEPOCHLEN
Definition: utility.h:80
void syserror(const char *message)
Definition: utility.cpp:348
long long int64_t
Definition: int64.h:51
std::string m_errmsg
Definition: utility.h:285
void check_config()
Definition: utility.cpp:842
std::string m_pattern
Definition: utility.h:282
const char * format_capacity(char *str, int strsize, uint64_t val, const char *decimal_point)
Definition: utility.cpp:736
void pout(const char *fmt,...)
Definition: smartctl.cpp:1091
void copy(const regular_expression &x)
Definition: utility.cpp:469
std::string vstrprintf(const char *fmt, va_list ap)
Definition: utility.cpp:779
ptr_t buffer
Definition: megaraid.h:89
Wrapper class for regex(3).
Definition: utility.h:235
regular_expression & operator=(const regular_expression &x)
Definition: utility.cpp:454
int split_report_arg(char *s, int *i)
Definition: utility.cpp:520
const char * format_with_thousands_sep(char *str, int strsize, uint64_t val, const char *thousands_sep)
Definition: utility.cpp:704
unsigned long long uint64_t
Definition: int64.h:54
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:787
int safe_snprintf(char *buf, int size, const char *fmt,...)
Definition: utility.cpp:818
int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
Definition: utility.cpp:806
uint64_t strtoull(const char *p, char **endp, int base)
Definition: utility.cpp:545
static void check_endianness()
Definition: utility.cpp:268
int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode)
Definition: utility.cpp:596
#define UTILITY_H_CVSID
Definition: utility.h:28