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-14 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 3871 2014-01-01 16:28:01Z 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-14, 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 +=
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 configure arguments: "
00120   ;
00121   info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
00122            SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]");
00123   info += '\n';
00124 
00125   return info;
00126 }
00127 
00128 // Solaris only: Get site-default timezone. This is called from
00129 // UpdateTimezone() when TZ environment variable is unset at startup.
00130 #if defined (__SVR4) && defined (__sun)
00131 static const char *TIMEZONE_FILE = "/etc/TIMEZONE";
00132 
00133 static char *ReadSiteDefaultTimezone(){
00134   FILE *fp;
00135   char buf[512], *tz;
00136   int n;
00137 
00138   tz = NULL;
00139   fp = fopen(TIMEZONE_FILE, "r");
00140   if(fp == NULL) return NULL;
00141   while(fgets(buf, sizeof(buf), fp)) {
00142     if (strncmp(buf, "TZ=", 3))    // searches last "TZ=" line
00143       continue;
00144     n = strlen(buf) - 1;
00145     if (buf[n] == '\n') buf[n] = 0;
00146     if (tz) free(tz);
00147     tz = strdup(buf);
00148   }
00149   fclose(fp);
00150   return tz;
00151 }
00152 #endif
00153 
00154 // Make sure that this executable is aware if the user has changed the
00155 // time-zone since the last time we polled devices. The cannonical
00156 // example is a user who starts smartd on a laptop, then flies across
00157 // time-zones with a laptop, and then changes the timezone, WITHOUT
00158 // restarting smartd. This is a work-around for a bug in
00159 // GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and
00160 // thanks to Ian Redfern for posting a workaround.
00161 
00162 // Please refer to the smartd manual page, in the section labeled LOG
00163 // TIMESTAMP TIMEZONE.
00164 void FixGlibcTimeZoneBug(){
00165 #if __GLIBC__  
00166   if (!getenv("TZ")) {
00167     putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
00168     tzset();
00169     putenv((char *)"TZ");
00170     tzset();
00171   }
00172 #elif _WIN32
00173   if (!getenv("TZ")) {
00174     putenv("TZ=GMT");
00175     tzset();
00176     putenv("TZ=");  // empty value removes TZ, putenv("TZ") does nothing
00177     tzset();
00178   }
00179 #elif defined (__SVR4) && defined (__sun)
00180   // In Solaris, putenv("TZ=") sets null string and invalid timezone.
00181   // putenv("TZ") does nothing.  With invalid TZ, tzset() do as if
00182   // TZ=GMT.  With TZ unset, /etc/TIMEZONE will be read only _once_ at
00183   // first tzset() call.  Conclusion: Unlike glibc, dynamic
00184   // configuration of timezone can be done only by changing actual
00185   // value of TZ environment value.
00186   enum tzstate { NOT_CALLED_YET, USER_TIMEZONE, TRACK_TIMEZONE };
00187   static enum tzstate state = NOT_CALLED_YET;
00188 
00189   static struct stat prev_stat;
00190   static char *prev_tz;
00191   struct stat curr_stat;
00192   char *curr_tz;
00193 
00194   if(state == NOT_CALLED_YET) {
00195     if(getenv("TZ")) {
00196       state = USER_TIMEZONE; // use supplied timezone
00197     } else {
00198       state = TRACK_TIMEZONE;
00199       if(stat(TIMEZONE_FILE, &prev_stat)) {
00200         state = USER_TIMEZONE;  // no TZ, no timezone file; use GMT forever
00201       } else {
00202         prev_tz = ReadSiteDefaultTimezone(); // track timezone file change
00203         if(prev_tz) putenv(prev_tz);
00204       }
00205     }
00206     tzset();
00207   } else if(state == TRACK_TIMEZONE) {
00208     if(stat(TIMEZONE_FILE, &curr_stat) == 0
00209        && (curr_stat.st_ctime != prev_stat.st_ctime
00210             || curr_stat.st_mtime != prev_stat.st_mtime)) {
00211       // timezone file changed
00212       curr_tz = ReadSiteDefaultTimezone();
00213       if(curr_tz) {
00214         putenv(curr_tz);
00215         if(prev_tz) free(prev_tz);
00216         prev_tz = curr_tz; prev_stat = curr_stat; 
00217       }
00218     }
00219     tzset();
00220   }
00221 #endif
00222   // OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED.  PLEASE TRY TO
00223   // KEEP THEM INDEPENDENT.
00224   return;
00225 }
00226 
00227 #ifdef _WIN32
00228 // Fix strings in tzname[] to avoid long names with non-ascii characters.
00229 // If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
00230 // national language timezone names returned by GetTimezoneInformation().
00231 static char * fixtzname(char * dest, int destsize, const char * src)
00232 {
00233   int i = 0, j = 0;
00234   while (src[i] && j < destsize-1) {
00235     int i2 = (const char *)_mbsinc((const unsigned char *)src+i) - src;
00236     if (i2 > i+1)
00237       i = i2; // Ignore multibyte chars
00238     else {
00239       if ('A' <= src[i] && src[i] <= 'Z')
00240         dest[j++] = src[i]; // "Pacific Standard Time" => "PST"
00241       i++;
00242     }
00243   }
00244   if (j < 2)
00245     j = 0;
00246   dest[j] = 0;
00247   return dest;
00248 }
00249 #endif // _WIN32
00250 
00251 // This value follows the peripheral device type value as defined in
00252 // SCSI Primary Commands, ANSI INCITS 301:1997.  It is also used in
00253 // the ATA standard for packet devices to define the device type.
00254 const char *packetdevicetype(int type){
00255   if (type<0x10)
00256     return packet_types[type];
00257   
00258   if (type<0x20)
00259     return "Reserved";
00260   
00261   return "Unknown";
00262 }
00263 
00264 // Runtime check of byte ordering, throws if different from isbigendian().
00265 void check_endianness()
00266 {
00267   union {
00268     // Force compile error if int type is not 32bit.
00269     unsigned char c[sizeof(unsigned) == 4 ? 4 : -1];
00270     unsigned i;
00271   } x = {{1,2,3,4}};
00272 
00273   int big = -1;
00274   switch (x.i) {
00275     case 0x01020304: big = 1; break;
00276     case 0x04030201: big = 0; break;
00277   }
00278 
00279   if (big != (isbigendian() ? 1 : 0))
00280     throw std::logic_error("CPU endianness does not match compile time test");
00281 }
00282 
00283 // Utility function prints date and time and timezone into a character
00284 // buffer of length>=64.  All the fuss is needed to get the right
00285 // timezone info (sigh).
00286 void dateandtimezoneepoch(char *buffer, time_t tval){
00287   struct tm *tmval;
00288   const char *timezonename;
00289   char datebuffer[DATEANDEPOCHLEN];
00290   int lenm1;
00291 #ifdef _WIN32
00292   char tzfixbuf[6+1];
00293 #endif
00294 
00295   FixGlibcTimeZoneBug();
00296   
00297   // Get the time structure.  We need this to determine if we are in
00298   // daylight savings time or not.
00299   tmval=localtime(&tval);
00300   
00301   // Convert to an ASCII string, put in datebuffer
00302   // same as: asctime_r(tmval, datebuffer);
00303   strncpy(datebuffer, asctime(tmval), DATEANDEPOCHLEN);
00304   datebuffer[DATEANDEPOCHLEN-1]='\0';
00305   
00306   // Remove newline
00307   lenm1=strlen(datebuffer)-1;
00308   datebuffer[lenm1>=0?lenm1:0]='\0';
00309   
00310   // correct timezone name
00311   if (tmval->tm_isdst==0)
00312     // standard time zone
00313     timezonename=tzname[0];
00314   else if (tmval->tm_isdst>0)
00315     // daylight savings in effect
00316     timezonename=tzname[1];
00317   else
00318     // unable to determine if daylight savings in effect
00319     timezonename="";
00320 
00321 #ifdef _WIN32
00322   // Fix long non-ascii timezone names
00323   if (!getenv("TZ"))
00324     timezonename=fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename);
00325 #endif
00326   
00327   // Finally put the information into the buffer as needed.
00328   snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename);
00329   
00330   return;
00331 }
00332 
00333 // Date and timezone gets printed into string pointed to by buffer
00334 void dateandtimezone(char *buffer){
00335   
00336   // Get the epoch (time in seconds since Jan 1 1970)
00337   time_t tval=time(NULL);
00338   
00339   dateandtimezoneepoch(buffer, tval);
00340   return;
00341 }
00342 
00343 // A replacement for perror() that sends output to our choice of
00344 // printing. If errno not set then just print message.
00345 void syserror(const char *message){
00346   
00347   if (errno) {
00348     // Get the correct system error message:
00349     const char *errormessage=strerror(errno);
00350     
00351     // Check that caller has handed a sensible string, and provide
00352     // appropriate output. See perrror(3) man page to understand better.
00353     if (message && *message)
00354       pout("%s: %s\n",message, errormessage);
00355     else
00356       pout("%s\n",errormessage);
00357   }
00358   else if (message && *message)
00359     pout("%s\n",message);
00360   
00361   return;
00362 }
00363 
00364 // Check regular expression for non-portable features.
00365 //
00366 // POSIX extended regular expressions interpret unmatched ')' ordinary:
00367 // "The close-parenthesis shall be considered special in this context
00368 //  only if matched with a preceding open-parenthesis."
00369 //
00370 // GNU libc and BSD libc support unmatched ')', Cygwin reports an error.
00371 //
00372 // POSIX extended regular expressions do not define empty subexpressions:
00373 // "A vertical-line appearing first or last in an ERE, or immediately following
00374 //  a vertical-line or a left-parenthesis, or immediately preceding a
00375 //  right-parenthesis, produces undefined results."
00376 //
00377 // GNU libc and Cygwin support empty subexpressions, BSD libc reports an error.
00378 //
00379 static const char * check_regex(const char * pattern)
00380 {
00381   int level = 0;
00382   char c;
00383 
00384   for (int i = 0; (c = pattern[i]); i++) {
00385     // Skip "\x"
00386     if (c == '\\') {
00387       if (!pattern[++i])
00388         break;
00389       continue;
00390     }
00391 
00392     // Skip "[...]"
00393     if (c == '[') {
00394       if (pattern[++i] == '^')
00395         i++;
00396       if (!pattern[i++])
00397         break;
00398       while ((c = pattern[i]) && c != ']')
00399         i++;
00400       if (!c)
00401         break;
00402       continue;
00403     }
00404 
00405     // Check "(...)" nesting
00406     if (c == '(')
00407       level++;
00408     else if (c == ')' && --level < 0)
00409       return "Unmatched ')'";
00410 
00411     // Check for leading/trailing '|' or "||", "|)", "|$", "(|", "^|"
00412     char c1;
00413     if (   (c == '|' && (   i == 0 || !(c1 = pattern[i+1])
00414                           || c1 == '|' || c1 == ')' || c1 == '$'))
00415         || ((c == '(' || c == '^') && pattern[i+1] == '|')       )
00416       return "Empty '|' subexpression";
00417   }
00418 
00419   return (const char *)0;
00420 }
00421 
00422 // Wrapper class for regex(3)
00423 
00424 regular_expression::regular_expression()
00425 : m_flags(0)
00426 {
00427   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00428 }
00429 
00430 regular_expression::regular_expression(const char * pattern, int flags,
00431                                        bool throw_on_error /*= true*/)
00432 {
00433   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00434   if (!compile(pattern, flags) && throw_on_error)
00435     throw std::runtime_error(strprintf(
00436       "error in regular expression \"%s\": %s",
00437       m_pattern.c_str(), m_errmsg.c_str()));
00438 }
00439 
00440 regular_expression::~regular_expression()
00441 {
00442   free_buf();
00443 }
00444 
00445 regular_expression::regular_expression(const regular_expression & x)
00446 {
00447   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00448   copy(x);
00449 }
00450 
00451 regular_expression & regular_expression::operator=(const regular_expression & x)
00452 {
00453   free_buf();
00454   copy(x);
00455   return *this;
00456 }
00457 
00458 void regular_expression::free_buf()
00459 {
00460   if (nonempty(&m_regex_buf, sizeof(m_regex_buf))) {
00461     regfree(&m_regex_buf);
00462     memset(&m_regex_buf, 0, sizeof(m_regex_buf));
00463   }
00464 }
00465 
00466 void regular_expression::copy(const regular_expression & x)
00467 {
00468   m_pattern = x.m_pattern;
00469   m_flags = x.m_flags;
00470   m_errmsg = x.m_errmsg;
00471 
00472   if (!m_pattern.empty() && m_errmsg.empty()) {
00473     // There is no POSIX compiled-regex-copy command.
00474     if (!compile())
00475       throw std::runtime_error(strprintf(
00476         "Unable to recompile regular expression \"%s\": %s",
00477         m_pattern.c_str(), m_errmsg.c_str()));
00478   }
00479 }
00480 
00481 bool regular_expression::compile(const char * pattern, int flags)
00482 {
00483   free_buf();
00484   m_pattern = pattern;
00485   m_flags = flags;
00486   return compile();
00487 }
00488 
00489 bool regular_expression::compile()
00490 {
00491   int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), m_flags);
00492   if (errcode) {
00493     char errmsg[512];
00494     regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg));
00495     m_errmsg = errmsg;
00496     free_buf();
00497     return false;
00498   }
00499 
00500   const char * errmsg = check_regex(m_pattern.c_str());
00501   if (errmsg) {
00502     m_errmsg = errmsg;
00503     free_buf();
00504     return false;
00505   }
00506 
00507   m_errmsg.clear();
00508   return true;
00509 }
00510 
00511 // Splits an argument to the -r option into a name part and an (optional) 
00512 // positive integer part.  s is a pointer to a string containing the
00513 // argument.  After the call, s will point to the name part and *i the
00514 // integer part if there is one or 1 otherwise.  Note that the string s may
00515 // be changed by this function.  Returns zero if successful and non-zero
00516 // otherwise.
00517 int split_report_arg(char *s, int *i)
00518 {
00519   if ((s = strchr(s, ','))) {
00520     // Looks like there's a name part and an integer part.
00521     char *tailptr;
00522 
00523     *s++ = '\0';
00524     if (*s == '0' || !isdigit((int)*s))  // The integer part must be positive
00525       return 1;
00526     errno = 0;
00527     *i = (int) strtol(s, &tailptr, 10);
00528     if (errno || *tailptr != '\0')
00529       return 1;
00530   } else {
00531     // There's no integer part.
00532     *i = 1;
00533   }
00534 
00535   return 0;
00536 }
00537 
00538 #ifndef HAVE_STRTOULL
00539 // Replacement for missing strtoull() (Linux with libc < 6, MSVC)
00540 // Functionality reduced to requirements of smartd and split_selective_arg().
00541 
00542 uint64_t strtoull(const char * p, char * * endp, int base)
00543 {
00544   uint64_t result, maxres;
00545   int i = 0;
00546   char c = p[i++];
00547 
00548   if (!base) {
00549     if (c == '0') {
00550       if (p[i] == 'x' || p[i] == 'X') {
00551         base = 16; i++;
00552       }
00553       else
00554         base = 8;
00555       c = p[i++];
00556     }
00557     else
00558       base = 10;
00559   }
00560 
00561   result = 0;
00562   maxres = ~(uint64_t)0 / (unsigned)base;
00563   for (;;) {
00564     unsigned digit;
00565     if ('0' <= c && c <= '9')
00566       digit = c - '0';
00567     else if ('A' <= c && c <= 'Z')
00568       digit = c - 'A' + 10;
00569     else if ('a' <= c && c <= 'z')
00570       digit = c - 'a' + 10;
00571     else
00572       break;
00573     if (digit >= (unsigned)base)
00574       break;
00575     if (!(   result < maxres
00576           || (result == maxres && digit <= ~(uint64_t)0 % (unsigned)base))) {
00577       result = ~(uint64_t)0; errno = ERANGE; // return on overflow
00578       break;
00579     }
00580     result = result * (unsigned)base + digit;
00581     c = p[i++];
00582   }
00583   if (endp)
00584     *endp = (char *)p + i - 1;
00585   return result;
00586 }
00587 #endif // HAVE_STRTOLL
00588 
00589 // Splits an argument to the -t option that is assumed to be of the form
00590 // "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex)
00591 // are allowed).  The first long long int is assigned to *start and the second
00592 // to *stop.  Returns zero if successful and non-zero otherwise.
00593 int split_selective_arg(char *s, uint64_t *start,
00594                         uint64_t *stop, int *mode)
00595 {
00596   char *tailptr;
00597   if (!(s = strchr(s, ',')))
00598     return 1;
00599   bool add = false;
00600   if (!isdigit((int)(*++s))) {
00601     *start = *stop = 0;
00602     if (!strncmp(s, "redo", 4))
00603       *mode = SEL_REDO;
00604     else if (!strncmp(s, "next", 4))
00605       *mode = SEL_NEXT;
00606     else if (!strncmp(s, "cont", 4))
00607       *mode = SEL_CONT;
00608     else
00609       return 1;
00610     s += 4;
00611     if (!*s)
00612       return 0;
00613     if (*s != '+')
00614       return 1;
00615   }
00616   else {
00617     *mode = SEL_RANGE;
00618     errno = 0;
00619     // Last argument to strtoull (the base) is 0 meaning that decimal is assumed
00620     // unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used.
00621     *start = strtoull(s, &tailptr, 0);
00622     s = tailptr;
00623     add = (*s == '+');
00624     if (!(!errno && (add || *s == '-')))
00625       return 1;
00626     if (!strcmp(s, "-max")) {
00627       *stop = ~(uint64_t)0; // replaced by max LBA later
00628       return 0;
00629     }
00630   }
00631 
00632   errno = 0;
00633   *stop = strtoull(s+1, &tailptr, 0);
00634   if (errno || *tailptr != '\0')
00635     return 1;
00636   if (add) {
00637     if (*stop > 0)
00638       (*stop)--;
00639     *stop += *start; // -t select,N+M => -t select,N,(N+M-1)
00640   }
00641   return 0;
00642 }
00643 
00644 #ifdef OLD_INTERFACE
00645 
00646 int64_t bytes = 0;
00647 
00648 // Helps debugging.  If the second argument is non-negative, then
00649 // decrement bytes by that amount.  Else decrement bytes by (one plus)
00650 // length of null terminated string.
00651 void *FreeNonZero1(void *address, int size, int line, const char* file){
00652   if (address) {
00653     if (size<0)
00654       bytes-=1+strlen((char*)address);
00655     else
00656       bytes-=size;
00657     return CheckFree1(address, line, file);
00658   }
00659   return NULL;
00660 }
00661 
00662 // To help with memory checking.  Use when it is known that address is
00663 // NOT null.
00664 void *CheckFree1(void *address, int /*whatline*/, const char* /*file*/){
00665   if (address){
00666     free(address);
00667     return NULL;
00668   }
00669   throw std::runtime_error("Internal error in CheckFree()");
00670 }
00671 
00672 // A custom version of calloc() that tracks memory use
00673 void *Calloc(size_t nmemb, size_t size) { 
00674   void *ptr=calloc(nmemb, size);
00675   
00676   if (ptr)
00677     bytes+=nmemb*size;
00678 
00679   return ptr;
00680 }
00681 
00682 // A custom version of strdup() that keeps track of how much memory is
00683 // being allocated. If mustexist is set, it also throws an error if we
00684 // try to duplicate a NULL string.
00685 char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){
00686   char *tmp;
00687 
00688   // report error if ptr is NULL and mustexist is set
00689   if (ptr==NULL){
00690     if (mustexist)
00691       throw std::runtime_error("Internal error in CustomStrDup()");
00692     else
00693       return NULL;
00694   }
00695 
00696   // make a copy of the string...
00697   tmp=strdup(ptr);
00698   
00699   if (!tmp)
00700     throw std::bad_alloc();
00701   
00702   // and track memory usage
00703   bytes+=1+strlen(ptr);
00704   
00705   return tmp;
00706 }
00707 
00708 #endif // OLD_INTERFACE
00709 
00710 
00711 // Returns true if region of memory contains non-zero entries
00712 bool nonempty(const void * data, int size)
00713 {
00714   for (int i = 0; i < size; i++)
00715     if (((const unsigned char *)data)[i])
00716       return true;
00717   return false;
00718 }
00719 
00720 // Format integer with thousands separator
00721 const char * format_with_thousands_sep(char * str, int strsize, uint64_t val,
00722                                        const char * thousands_sep /* = 0 */)
00723 {
00724   if (!thousands_sep) {
00725     thousands_sep = ",";
00726 #ifdef HAVE_LOCALE_H
00727     setlocale(LC_ALL, "");
00728     const struct lconv * currentlocale = localeconv();
00729     if (*(currentlocale->thousands_sep))
00730       thousands_sep = currentlocale->thousands_sep;
00731 #endif
00732   }
00733 
00734   char num[64];
00735   snprintf(num, sizeof(num), "%" PRIu64, val);
00736   int numlen = strlen(num);
00737 
00738   int i = 0, j = 0;
00739   do
00740     str[j++] = num[i++];
00741   while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1);
00742   str[j] = 0;
00743 
00744   while (i < numlen && j < strsize-1) {
00745     j += snprintf(str+j, strsize-j, "%s%.3s", thousands_sep, num+i);
00746     i += 3;
00747   }
00748 
00749   return str;
00750 }
00751 
00752 // Format capacity with SI prefixes
00753 const char * format_capacity(char * str, int strsize, uint64_t val,
00754                              const char * decimal_point /* = 0 */)
00755 {
00756   if (!decimal_point) {
00757     decimal_point = ".";
00758 #ifdef HAVE_LOCALE_H
00759     setlocale(LC_ALL, "");
00760     const struct lconv * currentlocale = localeconv();
00761     if (*(currentlocale->decimal_point))
00762       decimal_point = currentlocale->decimal_point;
00763 #endif
00764   }
00765 
00766   const unsigned factor = 1000; // 1024 for KiB,MiB,...
00767   static const char prefixes[] = " KMGTP";
00768 
00769   // Find d with val in [d, d*factor)
00770   unsigned i = 0;
00771   uint64_t d = 1;
00772   for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) {
00773     d = d2;
00774     if (++i >= sizeof(prefixes)-2)
00775       break;
00776   }
00777 
00778   // Print 3 digits
00779   uint64_t n = val / d;
00780   if (i == 0)
00781     snprintf(str, strsize, "%u B", (unsigned)n);
00782   else if (n >= 100) // "123 xB"
00783     snprintf(str, strsize, "%" PRIu64 " %cB", n, prefixes[i]);
00784   else if (n >= 10)  // "12.3 xB"
00785     snprintf(str, strsize, "%" PRIu64 "%s%u %cB", n, decimal_point,
00786         (unsigned)(((val % d) * 10) / d), prefixes[i]);
00787   else               // "1.23 xB"
00788     snprintf(str, strsize, "%" PRIu64 "%s%02u %cB", n, decimal_point,
00789         (unsigned)(((val % d) * 100) / d), prefixes[i]);
00790 
00791   return str;
00792 }
00793 
00794 // return (v)sprintf() formatted std::string
00795 
00796 std::string vstrprintf(const char * fmt, va_list ap)
00797 {
00798   char buf[512];
00799   vsnprintf(buf, sizeof(buf), fmt, ap);
00800   buf[sizeof(buf)-1] = 0;
00801   return buf;
00802 }
00803 
00804 std::string strprintf(const char * fmt, ...)
00805 {
00806   va_list ap; va_start(ap, fmt);
00807   std::string str = vstrprintf(fmt, ap);
00808   va_end(ap);
00809   return str;
00810 }
00811 
00812 
00813 #ifndef HAVE_WORKING_SNPRINTF
00814 // Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL),
00815 // and/or return -1 on overflow (old Linux).
00816 // Below are sane replacements substituted by #define in utility.h.
00817 
00818 #undef vsnprintf
00819 #if defined(_WIN32) && defined(_MSC_VER)
00820 #define vsnprintf _vsnprintf
00821 #endif
00822 
00823 int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
00824 {
00825   int i;
00826   if (size <= 0)
00827     return 0;
00828   i = vsnprintf(buf, size, fmt, ap);
00829   if (0 <= i && i < size)
00830     return i;
00831   buf[size-1] = 0;
00832   return strlen(buf); // Note: cannot detect for overflow, not necessary here.
00833 }
00834 
00835 int safe_snprintf(char *buf, int size, const char *fmt, ...)
00836 {
00837   int i; va_list ap;
00838   va_start(ap, fmt);
00839   i = safe_vsnprintf(buf, size, fmt, ap);
00840   va_end(ap);
00841   return i;
00842 }
00843 
00844 #endif
00845