smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
utility.cpp
Go to the documentation of this file.
00001 /*
00002  * utility.cpp
00003  *
00004  * Home page of code is: http://smartmontools.sourceforge.net
00005  *
00006  * Copyright (C) 2002-12 Bruce Allen <smartmontools-support@lists.sourceforge.net>
00007  * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
00008  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * This code was originally developed as a Senior Thesis by Michael Cornwell
00019  * at the Concurrent Systems Laboratory (now part of the Storage Systems
00020  * Research Center), Jack Baskin School of Engineering, University of
00021  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
00022  *
00023  */
00024 
00025 // THIS FILE IS INTENDED FOR UTILITY ROUTINES THAT ARE APPLICABLE TO
00026 // BOTH SCSI AND ATA DEVICES, AND THAT MAY BE USED IN SMARTD,
00027 // SMARTCTL, OR BOTH.
00028 
00029 #include "config.h"
00030 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <time.h>
00034 #include <errno.h>
00035 #include <stdlib.h>
00036 #include <ctype.h>
00037 #include <stdarg.h>
00038 #include <sys/stat.h>
00039 #ifdef HAVE_LOCALE_H
00040 #include <locale.h>
00041 #endif
00042 #ifdef _WIN32
00043 #include <mbstring.h> // _mbsinc()
00044 #endif
00045 
00046 #include <stdexcept>
00047 
00048 #include "svnversion.h"
00049 #include "int64.h"
00050 #include "utility.h"
00051 
00052 #include "atacmds.h"
00053 #include "dev_interface.h"
00054 
00055 const char * utility_cpp_cvsid = "$Id: utility.cpp 3739 2013-01-01 16:32:48Z chrfranke $"
00056                                  UTILITY_H_CVSID INT64_H_CVSID;
00057 
00058 const char * packet_types[] = {
00059         "Direct-access (disk)",
00060         "Sequential-access (tape)",
00061         "Printer",
00062         "Processor",
00063         "Write-once (optical disk)",
00064         "CD/DVD",
00065         "Scanner",
00066         "Optical memory (optical disk)",
00067         "Medium changer",
00068         "Communications",
00069         "Graphic arts pre-press (10)",
00070         "Graphic arts pre-press (11)",
00071         "Array controller",
00072         "Enclosure services",
00073         "Reduced block command (simplified disk)",
00074         "Optical card reader/writer"
00075 };
00076 
00077 // BUILD_INFO can be provided by package maintainers
00078 #ifndef BUILD_INFO
00079 #define BUILD_INFO "(local build)"
00080 #endif
00081 
00082 // Make version information string
00083 std::string format_version_info(const char * prog_name, bool full /*= false*/)
00084 {
00085   std::string info = strprintf(
00086     "%s "PACKAGE_VERSION" "
00087 #ifdef SMARTMONTOOLS_SVN_REV
00088       SMARTMONTOOLS_SVN_DATE" r"SMARTMONTOOLS_SVN_REV
00089 #else
00090       "(build date "__DATE__")" // checkout without expansion of Id keywords
00091 #endif
00092       " [%s] "BUILD_INFO"\n"
00093     "Copyright (C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org\n",
00094     prog_name, smi()->get_os_version_str().c_str()
00095   );
00096   if (!full)
00097     return info;
00098 
00099   info += strprintf(
00100     "\n"
00101     "%s comes with ABSOLUTELY NO WARRANTY. This is free\n"
00102     "software, and you are welcome to redistribute it under\n"
00103     "the terms of the GNU General Public License; either\n"
00104     "version 2, or (at your option) any later version.\n"
00105     "See http://www.gnu.org for further details.\n"
00106     "\n",
00107     prog_name
00108   );
00109   info += strprintf(
00110     "smartmontools release "PACKAGE_VERSION
00111       " dated "SMARTMONTOOLS_RELEASE_DATE" at "SMARTMONTOOLS_RELEASE_TIME"\n"
00112 #ifdef SMARTMONTOOLS_SVN_REV
00113     "smartmontools SVN rev "SMARTMONTOOLS_SVN_REV
00114       " dated "SMARTMONTOOLS_SVN_DATE" at "SMARTMONTOOLS_SVN_TIME"\n"
00115 #else
00116     "smartmontools SVN rev is unknown\n"
00117 #endif
00118     "smartmontools build host: "SMARTMONTOOLS_BUILD_HOST"\n"
00119     "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n"
00120     "%s compile dated "__DATE__" at "__TIME__"\n"
00121     "smartmontools configure arguments: ",
00122     prog_name
00123   );
00124   info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
00125            SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]");
00126   info += '\n';
00127 
00128   return info;
00129 }
00130 
00131 // Solaris only: Get site-default timezone. This is called from
00132 // UpdateTimezone() when TZ environment variable is unset at startup.
00133 #if defined (__SVR4) && defined (__sun)
00134 static const char *TIMEZONE_FILE = "/etc/TIMEZONE";
00135 
00136 static char *ReadSiteDefaultTimezone(){
00137   FILE *fp;
00138   char buf[512], *tz;
00139   int n;
00140 
00141   tz = NULL;
00142   fp = fopen(TIMEZONE_FILE, "r");
00143   if(fp == NULL) return NULL;
00144   while(fgets(buf, sizeof(buf), fp)) {
00145     if (strncmp(buf, "TZ=", 3))    // searches last "TZ=" line
00146       continue;
00147     n = strlen(buf) - 1;
00148     if (buf[n] == '\n') buf[n] = 0;
00149     if (tz) free(tz);
00150     tz = strdup(buf);
00151   }
00152   fclose(fp);
00153   return tz;
00154 }
00155 #endif
00156 
00157 // Make sure that this executable is aware if the user has changed the
00158 // time-zone since the last time we polled devices. The cannonical
00159 // example is a user who starts smartd on a laptop, then flies across
00160 // time-zones with a laptop, and then changes the timezone, WITHOUT
00161 // restarting smartd. This is a work-around for a bug in
00162 // GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and
00163 // thanks to Ian Redfern for posting a workaround.
00164 
00165 // Please refer to the smartd manual page, in the section labeled LOG
00166 // TIMESTAMP TIMEZONE.
00167 void FixGlibcTimeZoneBug(){
00168 #if __GLIBC__  
00169   if (!getenv("TZ")) {
00170     putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
00171     tzset();
00172     putenv((char *)"TZ");
00173     tzset();
00174   }
00175 #elif _WIN32
00176   if (!getenv("TZ")) {
00177     putenv("TZ=GMT");
00178     tzset();
00179     putenv("TZ=");  // empty value removes TZ, putenv("TZ") does nothing
00180     tzset();
00181   }
00182 #elif defined (__SVR4) && defined (__sun)
00183   // In Solaris, putenv("TZ=") sets null string and invalid timezone.
00184   // putenv("TZ") does nothing.  With invalid TZ, tzset() do as if
00185   // TZ=GMT.  With TZ unset, /etc/TIMEZONE will be read only _once_ at
00186   // first tzset() call.  Conclusion: Unlike glibc, dynamic
00187   // configuration of timezone can be done only by changing actual
00188   // value of TZ environment value.
00189   enum tzstate { NOT_CALLED_YET, USER_TIMEZONE, TRACK_TIMEZONE };
00190   static enum tzstate state = NOT_CALLED_YET;
00191 
00192   static struct stat prev_stat;
00193   static char *prev_tz;
00194   struct stat curr_stat;
00195   char *curr_tz;
00196 
00197   if(state == NOT_CALLED_YET) {
00198     if(getenv("TZ")) {
00199       state = USER_TIMEZONE; // use supplied timezone
00200     } else {
00201       state = TRACK_TIMEZONE;
00202       if(stat(TIMEZONE_FILE, &prev_stat)) {
00203         state = USER_TIMEZONE;  // no TZ, no timezone file; use GMT forever
00204       } else {
00205         prev_tz = ReadSiteDefaultTimezone(); // track timezone file change
00206         if(prev_tz) putenv(prev_tz);
00207       }
00208     }
00209     tzset();
00210   } else if(state == TRACK_TIMEZONE) {
00211     if(stat(TIMEZONE_FILE, &curr_stat) == 0
00212        && (curr_stat.st_ctime != prev_stat.st_ctime
00213             || curr_stat.st_mtime != prev_stat.st_mtime)) {
00214       // timezone file changed
00215       curr_tz = ReadSiteDefaultTimezone();
00216       if(curr_tz) {
00217         putenv(curr_tz);
00218         if(prev_tz) free(prev_tz);
00219         prev_tz = curr_tz; prev_stat = curr_stat; 
00220       }
00221     }
00222     tzset();
00223   }
00224 #endif
00225   // OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED.  PLEASE TRY TO
00226   // KEEP THEM INDEPENDENT.
00227   return;
00228 }
00229 
00230 #ifdef _WIN32
00231 // Fix strings in tzname[] to avoid long names with non-ascii characters.
00232 // If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
00233 // national language timezone names returned by GetTimezoneInformation().
00234 static char * fixtzname(char * dest, int destsize, const char * src)
00235 {
00236   int i = 0, j = 0;
00237   while (src[i] && j < destsize-1) {
00238     int i2 = (const char *)_mbsinc((const unsigned char *)src+i) - src;
00239     if (i2 > i+1)
00240       i = i2; // Ignore multibyte chars
00241     else {
00242       if ('A' <= src[i] && src[i] <= 'Z')
00243         dest[j++] = src[i]; // "Pacific Standard Time" => "PST"
00244       i++;
00245     }
00246   }
00247   if (j < 2)
00248     j = 0;
00249   dest[j] = 0;
00250   return dest;
00251 }
00252 #endif // _WIN32
00253 
00254 // This value follows the peripheral device type value as defined in
00255 // SCSI Primary Commands, ANSI INCITS 301:1997.  It is also used in
00256 // the ATA standard for packet devices to define the device type.
00257 const char *packetdevicetype(int type){
00258   if (type<0x10)
00259     return packet_types[type];
00260   
00261   if (type<0x20)
00262     return "Reserved";
00263   
00264   return "Unknown";
00265 }
00266 
00267 // Runtime check of byte ordering, throws if different from isbigendian().
00268 void check_endianness()
00269 {
00270   union {
00271     // Force compile error if int type is not 32bit.
00272     unsigned char c[sizeof(unsigned) == 4 ? 4 : -1];
00273     unsigned i;
00274   } x = {{1,2,3,4}};
00275 
00276   int big = -1;
00277   switch (x.i) {
00278     case 0x01020304: big = 1; break;
00279     case 0x04030201: big = 0; break;
00280   }
00281 
00282   if (big != (isbigendian() ? 1 : 0))
00283     throw std::logic_error("CPU endianness does not match compile time test");
00284 }
00285 
00286 // Utility function prints date and time and timezone into a character
00287 // buffer of length>=64.  All the fuss is needed to get the right
00288 // timezone info (sigh).
00289 void dateandtimezoneepoch(char *buffer, time_t tval){
00290   struct tm *tmval;
00291   const char *timezonename;
00292   char datebuffer[DATEANDEPOCHLEN];
00293   int lenm1;
00294 #ifdef _WIN32
00295   char tzfixbuf[6+1];
00296 #endif
00297 
00298   FixGlibcTimeZoneBug();
00299   
00300   // Get the time structure.  We need this to determine if we are in
00301   // daylight savings time or not.
00302   tmval=localtime(&tval);
00303   
00304   // Convert to an ASCII string, put in datebuffer
00305   // same as: asctime_r(tmval, datebuffer);
00306   strncpy(datebuffer, asctime(tmval), DATEANDEPOCHLEN);
00307   datebuffer[DATEANDEPOCHLEN-1]='\0';
00308   
00309   // Remove newline
00310   lenm1=strlen(datebuffer)-1;
00311   datebuffer[lenm1>=0?lenm1:0]='\0';
00312   
00313   // correct timezone name
00314   if (tmval->tm_isdst==0)
00315     // standard time zone
00316     timezonename=tzname[0];
00317   else if (tmval->tm_isdst>0)
00318     // daylight savings in effect
00319     timezonename=tzname[1];
00320   else
00321     // unable to determine if daylight savings in effect
00322     timezonename="";
00323 
00324 #ifdef _WIN32
00325   // Fix long non-ascii timezone names
00326   if (!getenv("TZ"))
00327     timezonename=fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename);
00328 #endif
00329   
00330   // Finally put the information into the buffer as needed.
00331   snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename);
00332   
00333   return;
00334 }
00335 
00336 // Date and timezone gets printed into string pointed to by buffer
00337 void dateandtimezone(char *buffer){
00338   
00339   // Get the epoch (time in seconds since Jan 1 1970)
00340   time_t tval=time(NULL);
00341   
00342   dateandtimezoneepoch(buffer, tval);
00343   return;
00344 }
00345 
00346 // A replacement for perror() that sends output to our choice of
00347 // printing. If errno not set then just print message.
00348 void syserror(const char *message){
00349   
00350   if (errno) {
00351     // Get the correct system error message:
00352     const char *errormessage=strerror(errno);
00353     
00354     // Check that caller has handed a sensible string, and provide
00355     // appropriate output. See perrror(3) man page to understand better.
00356     if (message && *message)
00357       pout("%s: %s\n",message, errormessage);
00358     else
00359       pout("%s\n",errormessage);
00360   }
00361   else if (message && *message)
00362     pout("%s\n",message);
00363   
00364   return;
00365 }
00366 
00367 // POSIX extended regular expressions interpret unmatched ')' ordinary:
00368 // "The close-parenthesis shall be considered special in this context
00369 //  only if matched with a preceding open-parenthesis."
00370 //
00371 // Actual '(...)' nesting errors remain undetected on strict POSIX
00372 // implementations (glibc) but an error is reported on others (Cygwin).
00373 // 
00374 // The check below is rather incomplete because it does not handle
00375 // e.g. '\)' '[)]'.
00376 // But it should work for the regex subset used in drive database
00377 // and smartd '-s' directives.
00378 static int check_regex_nesting(const char * pattern)
00379 {
00380   int level = 0, i;
00381   for (i = 0; pattern[i] && level >= 0; i++) {
00382     switch (pattern[i]) {
00383       case '(': level++; break;
00384       case ')': level--; break;
00385     }
00386   }
00387   return level;
00388 }
00389 
00390 // Wrapper class for regex(3)
00391 
00392 regular_expression::regular_expression()
00393 : m_flags(0)
00394 {
00395   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00396 }
00397 
00398 regular_expression::regular_expression(const char * pattern, int flags,
00399                                        bool throw_on_error /*= true*/)
00400 {
00401   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00402   if (!compile(pattern, flags) && throw_on_error)
00403     throw std::runtime_error(strprintf(
00404       "error in regular expression \"%s\": %s",
00405       m_pattern.c_str(), m_errmsg.c_str()));
00406 }
00407 
00408 regular_expression::~regular_expression()
00409 {
00410   free_buf();
00411 }
00412 
00413 regular_expression::regular_expression(const regular_expression & x)
00414 {
00415   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00416   copy(x);
00417 }
00418 
00419 regular_expression & regular_expression::operator=(const regular_expression & x)
00420 {
00421   free_buf();
00422   copy(x);
00423   return *this;
00424 }
00425 
00426 void regular_expression::free_buf()
00427 {
00428   if (nonempty(&m_regex_buf, sizeof(m_regex_buf))) {
00429     regfree(&m_regex_buf);
00430     memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00431   }
00432 }
00433 
00434 void regular_expression::copy(const regular_expression & x)
00435 {
00436   m_pattern = x.m_pattern;
00437   m_flags = x.m_flags;
00438   m_errmsg = x.m_errmsg;
00439 
00440   if (!m_pattern.empty() && m_errmsg.empty()) {
00441     // There is no POSIX compiled-regex-copy command.
00442     if (!compile())
00443       throw std::runtime_error(strprintf(
00444         "Unable to recompile regular expression \"%s\": %s",
00445         m_pattern.c_str(), m_errmsg.c_str()));
00446   }
00447 }
00448 
00449 bool regular_expression::compile(const char * pattern, int flags)
00450 {
00451   free_buf();
00452   m_pattern = pattern;
00453   m_flags = flags;
00454   return compile();
00455 }
00456 
00457 bool regular_expression::compile()
00458 {
00459   int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), m_flags);
00460   if (errcode) {
00461     char errmsg[512];
00462     regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg));
00463     m_errmsg = errmsg;
00464     free_buf();
00465     return false;
00466   }
00467 
00468   if (check_regex_nesting(m_pattern.c_str()) < 0) {
00469     m_errmsg = "Unmatched ')'";
00470     free_buf();
00471     return false;
00472   }
00473 
00474   m_errmsg.clear();
00475   return true;
00476 }
00477 
00478 // Splits an argument to the -r option into a name part and an (optional) 
00479 // positive integer part.  s is a pointer to a string containing the
00480 // argument.  After the call, s will point to the name part and *i the
00481 // integer part if there is one or 1 otherwise.  Note that the string s may
00482 // be changed by this function.  Returns zero if successful and non-zero
00483 // otherwise.
00484 int split_report_arg(char *s, int *i)
00485 {
00486   if ((s = strchr(s, ','))) {
00487     // Looks like there's a name part and an integer part.
00488     char *tailptr;
00489 
00490     *s++ = '\0';
00491     if (*s == '0' || !isdigit((int)*s))  // The integer part must be positive
00492       return 1;
00493     errno = 0;
00494     *i = (int) strtol(s, &tailptr, 10);
00495     if (errno || *tailptr != '\0')
00496       return 1;
00497   } else {
00498     // There's no integer part.
00499     *i = 1;
00500   }
00501 
00502   return 0;
00503 }
00504 
00505 #ifndef HAVE_STRTOULL
00506 // Replacement for missing strtoull() (Linux with libc < 6, MSVC)
00507 // Functionality reduced to requirements of smartd and split_selective_arg().
00508 
00509 uint64_t strtoull(const char * p, char * * endp, int base)
00510 {
00511   uint64_t result, maxres;
00512   int i = 0;
00513   char c = p[i++];
00514 
00515   if (!base) {
00516     if (c == '0') {
00517       if (p[i] == 'x' || p[i] == 'X') {
00518         base = 16; i++;
00519       }
00520       else
00521         base = 8;
00522       c = p[i++];
00523     }
00524     else
00525       base = 10;
00526   }
00527 
00528   result = 0;
00529   maxres = ~(uint64_t)0 / (unsigned)base;
00530   for (;;) {
00531     unsigned digit;
00532     if ('0' <= c && c <= '9')
00533       digit = c - '0';
00534     else if ('A' <= c && c <= 'Z')
00535       digit = c - 'A' + 10;
00536     else if ('a' <= c && c <= 'z')
00537       digit = c - 'a' + 10;
00538     else
00539       break;
00540     if (digit >= (unsigned)base)
00541       break;
00542     if (!(   result < maxres
00543           || (result == maxres && digit <= ~(uint64_t)0 % (unsigned)base))) {
00544       result = ~(uint64_t)0; errno = ERANGE; // return on overflow
00545       break;
00546     }
00547     result = result * (unsigned)base + digit;
00548     c = p[i++];
00549   }
00550   if (endp)
00551     *endp = (char *)p + i - 1;
00552   return result;
00553 }
00554 #endif // HAVE_STRTOLL
00555 
00556 // Splits an argument to the -t option that is assumed to be of the form
00557 // "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex)
00558 // are allowed).  The first long long int is assigned to *start and the second
00559 // to *stop.  Returns zero if successful and non-zero otherwise.
00560 int split_selective_arg(char *s, uint64_t *start,
00561                         uint64_t *stop, int *mode)
00562 {
00563   char *tailptr;
00564   if (!(s = strchr(s, ',')))
00565     return 1;
00566   bool add = false;
00567   if (!isdigit((int)(*++s))) {
00568     *start = *stop = 0;
00569     if (!strncmp(s, "redo", 4))
00570       *mode = SEL_REDO;
00571     else if (!strncmp(s, "next", 4))
00572       *mode = SEL_NEXT;
00573     else if (!strncmp(s, "cont", 4))
00574       *mode = SEL_CONT;
00575     else
00576       return 1;
00577     s += 4;
00578     if (!*s)
00579       return 0;
00580     if (*s != '+')
00581       return 1;
00582   }
00583   else {
00584     *mode = SEL_RANGE;
00585     errno = 0;
00586     // Last argument to strtoull (the base) is 0 meaning that decimal is assumed
00587     // unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used.
00588     *start = strtoull(s, &tailptr, 0);
00589     s = tailptr;
00590     add = (*s == '+');
00591     if (!(!errno && (add || *s == '-')))
00592       return 1;
00593     if (!strcmp(s, "-max")) {
00594       *stop = ~(uint64_t)0; // replaced by max LBA later
00595       return 0;
00596     }
00597   }
00598 
00599   errno = 0;
00600   *stop = strtoull(s+1, &tailptr, 0);
00601   if (errno || *tailptr != '\0')
00602     return 1;
00603   if (add) {
00604     if (*stop > 0)
00605       (*stop)--;
00606     *stop += *start; // -t select,N+M => -t select,N,(N+M-1)
00607   }
00608   return 0;
00609 }
00610 
00611 #ifdef OLD_INTERFACE
00612 
00613 int64_t bytes = 0;
00614 
00615 // Helps debugging.  If the second argument is non-negative, then
00616 // decrement bytes by that amount.  Else decrement bytes by (one plus)
00617 // length of null terminated string.
00618 void *FreeNonZero1(void *address, int size, int line, const char* file){
00619   if (address) {
00620     if (size<0)
00621       bytes-=1+strlen((char*)address);
00622     else
00623       bytes-=size;
00624     return CheckFree1(address, line, file);
00625   }
00626   return NULL;
00627 }
00628 
00629 // To help with memory checking.  Use when it is known that address is
00630 // NOT null.
00631 void *CheckFree1(void *address, int /*whatline*/, const char* /*file*/){
00632   if (address){
00633     free(address);
00634     return NULL;
00635   }
00636   throw std::runtime_error("Internal error in CheckFree()");
00637 }
00638 
00639 // A custom version of calloc() that tracks memory use
00640 void *Calloc(size_t nmemb, size_t size) { 
00641   void *ptr=calloc(nmemb, size);
00642   
00643   if (ptr)
00644     bytes+=nmemb*size;
00645 
00646   return ptr;
00647 }
00648 
00649 // A custom version of strdup() that keeps track of how much memory is
00650 // being allocated. If mustexist is set, it also throws an error if we
00651 // try to duplicate a NULL string.
00652 char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){
00653   char *tmp;
00654 
00655   // report error if ptr is NULL and mustexist is set
00656   if (ptr==NULL){
00657     if (mustexist)
00658       throw std::runtime_error("Internal error in CustomStrDup()");
00659     else
00660       return NULL;
00661   }
00662 
00663   // make a copy of the string...
00664   tmp=strdup(ptr);
00665   
00666   if (!tmp)
00667     throw std::bad_alloc();
00668   
00669   // and track memory usage
00670   bytes+=1+strlen(ptr);
00671   
00672   return tmp;
00673 }
00674 
00675 #endif // OLD_INTERFACE
00676 
00677 
00678 // Returns true if region of memory contains non-zero entries
00679 bool nonempty(const void * data, int size)
00680 {
00681   for (int i = 0; i < size; i++)
00682     if (((const unsigned char *)data)[i])
00683       return true;
00684   return false;
00685 }
00686 
00687 // Format integer with thousands separator
00688 const char * format_with_thousands_sep(char * str, int strsize, uint64_t val,
00689                                        const char * thousands_sep /* = 0 */)
00690 {
00691   if (!thousands_sep) {
00692     thousands_sep = ",";
00693 #ifdef HAVE_LOCALE_H
00694     setlocale(LC_ALL, "");
00695     const struct lconv * currentlocale = localeconv();
00696     if (*(currentlocale->thousands_sep))
00697       thousands_sep = currentlocale->thousands_sep;
00698 #endif
00699   }
00700 
00701   char num[64];
00702   snprintf(num, sizeof(num), "%"PRIu64, val);
00703   int numlen = strlen(num);
00704 
00705   int i = 0, j = 0;
00706   do
00707     str[j++] = num[i++];
00708   while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1);
00709   str[j] = 0;
00710 
00711   while (i < numlen && j < strsize-1) {
00712     j += snprintf(str+j, strsize-j, "%s%.3s", thousands_sep, num+i);
00713     i += 3;
00714   }
00715 
00716   return str;
00717 }
00718 
00719 // Format capacity with SI prefixes
00720 const char * format_capacity(char * str, int strsize, uint64_t val,
00721                              const char * decimal_point /* = 0 */)
00722 {
00723   if (!decimal_point) {
00724     decimal_point = ".";
00725 #ifdef HAVE_LOCALE_H
00726     setlocale(LC_ALL, "");
00727     const struct lconv * currentlocale = localeconv();
00728     if (*(currentlocale->decimal_point))
00729       decimal_point = currentlocale->decimal_point;
00730 #endif
00731   }
00732 
00733   const unsigned factor = 1000; // 1024 for KiB,MiB,...
00734   static const char prefixes[] = " KMGTP";
00735 
00736   // Find d with val in [d, d*factor)
00737   unsigned i = 0;
00738   uint64_t d = 1;
00739   for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) {
00740     d = d2;
00741     if (++i >= sizeof(prefixes)-2)
00742       break;
00743   }
00744 
00745   // Print 3 digits
00746   uint64_t n = val / d;
00747   if (i == 0)
00748     snprintf(str, strsize, "%u B", (unsigned)n);
00749   else if (n >= 100) // "123 xB"
00750     snprintf(str, strsize, "%"PRIu64" %cB", n, prefixes[i]);
00751   else if (n >= 10)  // "12.3 xB"
00752     snprintf(str, strsize, "%"PRIu64"%s%u %cB", n, decimal_point,
00753         (unsigned)(((val % d) * 10) / d), prefixes[i]);
00754   else               // "1.23 xB"
00755     snprintf(str, strsize, "%"PRIu64"%s%02u %cB", n, decimal_point,
00756         (unsigned)(((val % d) * 100) / d), prefixes[i]);
00757 
00758   return str;
00759 }
00760 
00761 // return (v)sprintf() formatted std::string
00762 
00763 std::string vstrprintf(const char * fmt, va_list ap)
00764 {
00765   char buf[512];
00766   vsnprintf(buf, sizeof(buf), fmt, ap);
00767   buf[sizeof(buf)-1] = 0;
00768   return buf;
00769 }
00770 
00771 std::string strprintf(const char * fmt, ...)
00772 {
00773   va_list ap; va_start(ap, fmt);
00774   std::string str = vstrprintf(fmt, ap);
00775   va_end(ap);
00776   return str;
00777 }
00778 
00779 
00780 #ifndef HAVE_WORKING_SNPRINTF
00781 // Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL),
00782 // and/or return -1 on overflow (old Linux).
00783 // Below are sane replacements substituted by #define in utility.h.
00784 
00785 #undef vsnprintf
00786 #if defined(_WIN32) && defined(_MSC_VER)
00787 #define vsnprintf _vsnprintf
00788 #endif
00789 
00790 int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
00791 {
00792   int i;
00793   if (size <= 0)
00794     return 0;
00795   i = vsnprintf(buf, size, fmt, ap);
00796   if (0 <= i && i < size)
00797     return i;
00798   buf[size-1] = 0;
00799   return strlen(buf); // Note: cannot detect for overflow, not necessary here.
00800 }
00801 
00802 int safe_snprintf(char *buf, int size, const char *fmt, ...)
00803 {
00804   int i; va_list ap;
00805   va_start(ap, fmt);
00806   i = safe_vsnprintf(buf, size, fmt, ap);
00807   va_end(ap);
00808   return i;
00809 }
00810 
00811 #endif
00812