File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / utility.cpp
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:54:04 2013 UTC (10 years, 8 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, HEAD
v 6.2

    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-13 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,v 1.1.1.4 2013/10/14 07:54:04 misho Exp $"
   56:                                  UTILITY_H_CVSID INT64_H_CVSID;
   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-13, 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 += strprintf(
  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:     "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n"
  120:     "%s compile dated "__DATE__" at "__TIME__"\n"
  121:     "smartmontools configure arguments: ",
  122:     prog_name
  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.
  167: void FixGlibcTimeZoneBug(){
  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: 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: 
  298:   FixGlibcTimeZoneBug();
  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
  337: void dateandtimezone(char *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: 
  427: regular_expression::regular_expression()
  428: : m_flags(0)
  429: {
  430:   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
  431: }
  432: 
  433: regular_expression::regular_expression(const char * pattern, int flags,
  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: 
  443: regular_expression::~regular_expression()
  444: {
  445:   free_buf();
  446: }
  447: 
  448: regular_expression::regular_expression(const regular_expression & x)
  449: {
  450:   memset(&m_regex_buf, 0, sizeof(m_regex_buf));
  451:   copy(x);
  452: }
  453: 
  454: regular_expression & regular_expression::operator=(const regular_expression & x)
  455: {
  456:   free_buf();
  457:   copy(x);
  458:   return *this;
  459: }
  460: 
  461: void regular_expression::free_buf()
  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: 
  469: void regular_expression::copy(const regular_expression & x)
  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: 
  492: bool regular_expression::compile()
  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 *FreeNonZero1(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:     return CheckFree1(address, line, file);
  661:   }
  662:   return NULL;
  663: }
  664: 
  665: // To help with memory checking.  Use when it is known that address is
  666: // NOT null.
  667: void *CheckFree1(void *address, int /*whatline*/, const char* /*file*/){
  668:   if (address){
  669:     free(address);
  670:     return NULL;
  671:   }
  672:   throw std::runtime_error("Internal error in CheckFree()");
  673: }
  674: 
  675: // A custom version of calloc() that tracks memory use
  676: void *Calloc(size_t nmemb, size_t size) { 
  677:   void *ptr=calloc(nmemb, size);
  678:   
  679:   if (ptr)
  680:     bytes+=nmemb*size;
  681: 
  682:   return ptr;
  683: }
  684: 
  685: // A custom version of strdup() that keeps track of how much memory is
  686: // being allocated. If mustexist is set, it also throws an error if we
  687: // try to duplicate a NULL string.
  688: char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){
  689:   char *tmp;
  690: 
  691:   // report error if ptr is NULL and mustexist is set
  692:   if (ptr==NULL){
  693:     if (mustexist)
  694:       throw std::runtime_error("Internal error in CustomStrDup()");
  695:     else
  696:       return NULL;
  697:   }
  698: 
  699:   // make a copy of the string...
  700:   tmp=strdup(ptr);
  701:   
  702:   if (!tmp)
  703:     throw std::bad_alloc();
  704:   
  705:   // and track memory usage
  706:   bytes+=1+strlen(ptr);
  707:   
  708:   return tmp;
  709: }
  710: 
  711: #endif // OLD_INTERFACE
  712: 
  713: 
  714: // Returns true if region of memory contains non-zero entries
  715: bool nonempty(const void * data, int size)
  716: {
  717:   for (int i = 0; i < size; i++)
  718:     if (((const unsigned char *)data)[i])
  719:       return true;
  720:   return false;
  721: }
  722: 
  723: // Format integer with thousands separator
  724: const char * format_with_thousands_sep(char * str, int strsize, uint64_t val,
  725:                                        const char * thousands_sep /* = 0 */)
  726: {
  727:   if (!thousands_sep) {
  728:     thousands_sep = ",";
  729: #ifdef HAVE_LOCALE_H
  730:     setlocale(LC_ALL, "");
  731:     const struct lconv * currentlocale = localeconv();
  732:     if (*(currentlocale->thousands_sep))
  733:       thousands_sep = currentlocale->thousands_sep;
  734: #endif
  735:   }
  736: 
  737:   char num[64];
  738:   snprintf(num, sizeof(num), "%"PRIu64, val);
  739:   int numlen = strlen(num);
  740: 
  741:   int i = 0, j = 0;
  742:   do
  743:     str[j++] = num[i++];
  744:   while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1);
  745:   str[j] = 0;
  746: 
  747:   while (i < numlen && j < strsize-1) {
  748:     j += snprintf(str+j, strsize-j, "%s%.3s", thousands_sep, num+i);
  749:     i += 3;
  750:   }
  751: 
  752:   return str;
  753: }
  754: 
  755: // Format capacity with SI prefixes
  756: const char * format_capacity(char * str, int strsize, uint64_t val,
  757:                              const char * decimal_point /* = 0 */)
  758: {
  759:   if (!decimal_point) {
  760:     decimal_point = ".";
  761: #ifdef HAVE_LOCALE_H
  762:     setlocale(LC_ALL, "");
  763:     const struct lconv * currentlocale = localeconv();
  764:     if (*(currentlocale->decimal_point))
  765:       decimal_point = currentlocale->decimal_point;
  766: #endif
  767:   }
  768: 
  769:   const unsigned factor = 1000; // 1024 for KiB,MiB,...
  770:   static const char prefixes[] = " KMGTP";
  771: 
  772:   // Find d with val in [d, d*factor)
  773:   unsigned i = 0;
  774:   uint64_t d = 1;
  775:   for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) {
  776:     d = d2;
  777:     if (++i >= sizeof(prefixes)-2)
  778:       break;
  779:   }
  780: 
  781:   // Print 3 digits
  782:   uint64_t n = val / d;
  783:   if (i == 0)
  784:     snprintf(str, strsize, "%u B", (unsigned)n);
  785:   else if (n >= 100) // "123 xB"
  786:     snprintf(str, strsize, "%"PRIu64" %cB", n, prefixes[i]);
  787:   else if (n >= 10)  // "12.3 xB"
  788:     snprintf(str, strsize, "%"PRIu64"%s%u %cB", n, decimal_point,
  789:         (unsigned)(((val % d) * 10) / d), prefixes[i]);
  790:   else               // "1.23 xB"
  791:     snprintf(str, strsize, "%"PRIu64"%s%02u %cB", n, decimal_point,
  792:         (unsigned)(((val % d) * 100) / d), prefixes[i]);
  793: 
  794:   return str;
  795: }
  796: 
  797: // return (v)sprintf() formatted std::string
  798: 
  799: std::string vstrprintf(const char * fmt, va_list ap)
  800: {
  801:   char buf[512];
  802:   vsnprintf(buf, sizeof(buf), fmt, ap);
  803:   buf[sizeof(buf)-1] = 0;
  804:   return buf;
  805: }
  806: 
  807: std::string strprintf(const char * fmt, ...)
  808: {
  809:   va_list ap; va_start(ap, fmt);
  810:   std::string str = vstrprintf(fmt, ap);
  811:   va_end(ap);
  812:   return str;
  813: }
  814: 
  815: 
  816: #ifndef HAVE_WORKING_SNPRINTF
  817: // Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL),
  818: // and/or return -1 on overflow (old Linux).
  819: // Below are sane replacements substituted by #define in utility.h.
  820: 
  821: #undef vsnprintf
  822: #if defined(_WIN32) && defined(_MSC_VER)
  823: #define vsnprintf _vsnprintf
  824: #endif
  825: 
  826: int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap)
  827: {
  828:   int i;
  829:   if (size <= 0)
  830:     return 0;
  831:   i = vsnprintf(buf, size, fmt, ap);
  832:   if (0 <= i && i < size)
  833:     return i;
  834:   buf[size-1] = 0;
  835:   return strlen(buf); // Note: cannot detect for overflow, not necessary here.
  836: }
  837: 
  838: int safe_snprintf(char *buf, int size, const char *fmt, ...)
  839: {
  840:   int i; va_list ap;
  841:   va_start(ap, fmt);
  842:   i = safe_vsnprintf(buf, size, fmt, ap);
  843:   va_end(ap);
  844:   return i;
  845: }
  846: 
  847: #endif
  848: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>