Annotation of embedaddon/smartmontools/utility.cpp, revision 1.1.1.4

1.1       misho       1: /*
                      2:  * utility.cpp
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
1.1.1.2   misho       6:  * Copyright (C) 2002-12 Bruce Allen <smartmontools-support@lists.sourceforge.net>
1.1.1.3   misho       7:  * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
1.1       misho       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
1.1.1.3   misho      16:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
1.1       misho      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: 
1.1.1.4 ! misho      55: const char * utility_cpp_cvsid = "$Id: utility.cpp 3838 2013-07-21 16:32:27Z chrfranke $"
1.1       misho      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"
1.1.1.3   misho      93:     "Copyright (C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org\n",
1.1       misho      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"
1.1.1.2   misho     103:     "the terms of the GNU General Public License; either\n"
                    104:     "version 2, or (at your option) any later version.\n"
1.1       misho     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: 
1.1.1.4 ! misho     367: // Check regular expression for non-portable features.
        !           368: //
1.1       misho     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: //
1.1.1.4 ! misho     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;
1.1       misho     393:     }
1.1.1.4 ! misho     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";
1.1       misho     420:   }
1.1.1.4 ! misho     421: 
        !           422:   return (const char *)0;
1.1       misho     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: 
1.1.1.4 ! misho     503:   const char * errmsg = check_regex(m_pattern.c_str());
        !           504:   if (errmsg) {
        !           505:     m_errmsg = errmsg;
1.1       misho     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:   }
1.1.1.3   misho     634: 
                    635:   errno = 0;
1.1       misho     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>