~ubuntu-branches/ubuntu/natty/smartmontools/natty

« back to all changes in this revision

Viewing changes to utility.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Rivera
  • Date: 2010-06-29 09:44:50 UTC
  • mfrom: (2.2.12 sid)
  • Revision ID: james.westby@ubuntu.com-20100629094450-01lc0ux4e8a5mg70
Tags: 5.39.1+svn3077-1ubuntu1
* Merge from Debian unstable (LP: #599374), remaining changes:
  - Don't warn about being disabled unless verbose

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 *
4
4
 * Home page of code is: http://smartmontools.sourceforge.net
5
5
 *
6
 
 * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
6
 * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
7
 * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
7
8
 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8
9
 *
9
10
 * This program is free software; you can redistribute it and/or modify
39
40
#include <mbstring.h> // _mbsinc()
40
41
#endif
41
42
 
 
43
#include <stdexcept>
 
44
 
42
45
#include "config.h"
 
46
#include "svnversion.h"
43
47
#include "int64.h"
44
48
#include "utility.h"
45
49
 
46
 
// Any local header files should be represented by a CVSIDX just below.
47
 
const char* utility_c_cvsid="$Id: utility.cpp,v 1.65 2008/03/04 22:09:47 ballen4705 Exp $"
48
 
CONFIG_H_CVSID INT64_H_CVSID UTILITY_H_CVSID;
 
50
#include "atacmds.h"
 
51
#include "dev_interface.h"
 
52
 
 
53
const char * utility_cpp_cvsid = "$Id: utility.cpp 3022 2010-01-01 17:02:00Z chrfranke $"
 
54
                                 UTILITY_H_CVSID INT64_H_CVSID;
49
55
 
50
56
const char * packet_types[] = {
51
57
        "Direct-access (disk)",
70
76
const char *reportbug="Please report this bug to the Smartmontools developers at " PACKAGE_BUGREPORT ".\n";
71
77
 
72
78
 
73
 
// hang on to exit code, so we can make use of more generic 'atexit()'
74
 
// functionality and still check our exit code
75
 
int exitstatus = 0;
76
 
 
77
79
// command-line argument: are we running in debug mode?.
78
80
unsigned char debugmode = 0;
79
81
 
 
82
// BUILD_INFO can be provided by package maintainers
 
83
#ifndef BUILD_INFO
 
84
#define BUILD_INFO "(local build)"
 
85
#endif
 
86
 
 
87
// Make version information string
 
88
std::string format_version_info(const char * prog_name, bool full /*= false*/)
 
89
{
 
90
  std::string info = strprintf(
 
91
    "%s "PACKAGE_VERSION" "SMARTMONTOOLS_SVN_DATE" r"SMARTMONTOOLS_SVN_REV
 
92
      " [%s] "BUILD_INFO"\n"
 
93
    "Copyright (C) 2002-10 by Bruce Allen, http://smartmontools.sourceforge.net\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 Version 2.\n"
 
104
    "See http://www.gnu.org for further details.\n"
 
105
    "\n",
 
106
    prog_name
 
107
  );
 
108
  info += strprintf(
 
109
    "smartmontools release "PACKAGE_VERSION
 
110
      " dated "SMARTMONTOOLS_RELEASE_DATE" at "SMARTMONTOOLS_RELEASE_TIME"\n"
 
111
    "smartmontools SVN rev "SMARTMONTOOLS_SVN_REV
 
112
      " dated "SMARTMONTOOLS_SVN_DATE" at "SMARTMONTOOLS_SVN_TIME"\n"
 
113
    "smartmontools build host: "SMARTMONTOOLS_BUILD_HOST"\n"
 
114
    "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n"
 
115
    "%s compile dated "__DATE__" at "__TIME__"\n"
 
116
    "smartmontools configure arguments: ",
 
117
    prog_name
 
118
  );
 
119
  info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
 
120
           SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]");
 
121
  info += '\n';
 
122
 
 
123
  return info;
 
124
}
80
125
 
81
126
// Solaris only: Get site-default timezone. This is called from
82
127
// UpdateTimezone() when TZ environment variable is unset at startup.
117
162
void FixGlibcTimeZoneBug(){
118
163
#if __GLIBC__  
119
164
  if (!getenv("TZ")) {
120
 
    putenv("TZ=GMT");
 
165
    putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
121
166
    tzset();
122
 
    putenv("TZ");
 
167
    putenv((char *)"TZ");
123
168
    tzset();
124
169
  }
125
170
#elif _WIN32
230
275
// timezone info (sigh).
231
276
void dateandtimezoneepoch(char *buffer, time_t tval){
232
277
  struct tm *tmval;
233
 
  char *timezonename;
 
278
  const char *timezonename;
234
279
  char datebuffer[DATEANDEPOCHLEN];
235
280
  int lenm1;
236
281
#ifdef _WIN32
285
330
  return;
286
331
}
287
332
 
288
 
// These are two utility functions for printing CVS IDs. Massagecvs()
289
 
// returns distance that it has moved ahead in the input string
290
 
int massagecvs(char *out, const char *cvsid){
291
 
  char *copy,*filename,*date,*version;
292
 
  int retVal=0;
293
 
  const char delimiters[] = " ,$";
294
 
 
295
 
  // make a copy on the heap, go to first token,
296
 
  if (!(copy=strdup(cvsid)))
297
 
    return 0;
298
 
 
299
 
  if (!(filename=strtok(copy, delimiters)))
300
 
    goto endmassage;
301
 
 
302
 
  // move to first instance of "Id:"
303
 
  while (strcmp(filename,"Id:"))
304
 
    if (!(filename=strtok(NULL, delimiters)))
305
 
      goto endmassage;
306
 
  
307
 
  // get filename, skip "v", get version and date
308
 
  if (!(  filename=strtok(NULL, delimiters)  ) ||
309
 
      !(           strtok(NULL, delimiters)  ) ||
310
 
      !(   version=strtok(NULL, delimiters)  ) ||
311
 
      !(      date=strtok(NULL, delimiters)  ) )
312
 
    goto endmassage;
313
 
  
314
 
  sprintf(out,"%-16s revision: %-5s date: %-15s", filename, version, date);
315
 
  retVal = (date-copy)+strlen(date);
316
 
  
317
 
 endmassage:
318
 
  free(copy);
319
 
  return retVal;
320
 
}
321
 
 
322
 
// prints a single set of CVS ids
323
 
void printone(char *block, const char *cvsid){
324
 
  char strings[CVSMAXLEN];
325
 
  const char *here=cvsid;
326
 
  int bi=0, len=strlen(cvsid)+1;
327
 
 
328
 
  // check that the size of the output block is sufficient
329
 
  if (len>=CVSMAXLEN) {
330
 
    pout("CVSMAXLEN=%d must be at least %d\n",CVSMAXLEN,len+1);
331
 
    EXIT(1);
332
 
  }
333
 
 
334
 
  // loop through the different strings
335
 
  while (bi<CVSMAXLEN && (len=massagecvs(strings,here))){
336
 
    bi+=snprintf(block+bi,CVSMAXLEN-bi,"%s %s\n",(bi==0?"Module:":"  uses:"),strings);
337
 
    here+=len;
338
 
  }
339
 
  return;
340
 
}
341
 
 
342
 
 
343
333
// A replacement for perror() that sends output to our choice of
344
334
// printing. If errno not set then just print message.
345
335
void syserror(const char *message){
361
351
  return;
362
352
}
363
353
 
364
 
// Prints a warning message for a failed regular expression compilation from
365
 
// regcomp().
366
 
void printregexwarning(int errcode, regex_t *compiled){
367
 
  size_t length = regerror(errcode, compiled, NULL, 0);
368
 
  char *buffer = (char*)malloc(length);
369
 
  if (!buffer){
370
 
    pout("Out of memory in printregexwarning()\n");
371
 
    return;
372
 
  }
373
 
  regerror(errcode, compiled, buffer, length);
374
 
  pout("%s\n", buffer);
375
 
  free(buffer);
376
 
  return;
377
 
}
378
 
 
379
354
// POSIX extended regular expressions interpret unmatched ')' ordinary:
380
355
// "The close-parenthesis shall be considered special in this context
381
356
//  only if matched with a preceding open-parenthesis."
385
360
// 
386
361
// The check below is rather incomplete because it does not handle
387
362
// e.g. '\)' '[)]'.
388
 
// But it should work for the regex subset used in drive database.
 
363
// But it should work for the regex subset used in drive database
 
364
// and smartd '-s' directives.
389
365
static int check_regex_nesting(const char * pattern)
390
366
{
391
367
  int level = 0, i;
398
374
  return level;
399
375
}
400
376
 
401
 
// A wrapper for regcomp().  Returns zero for success, non-zero otherwise.
402
 
int compileregex(regex_t *compiled, const char *pattern, int cflags)
403
 
404
 
  int errorcode;
405
 
 
406
 
  if (   (errorcode = regcomp(compiled, pattern, cflags))
407
 
      || check_regex_nesting(pattern) < 0                ) {
408
 
    pout("Internal error: unable to compile regular expression \"%s\" ", pattern);
409
 
    if (errorcode)
410
 
      printregexwarning(errorcode, compiled);
411
 
    else
412
 
      pout("Unmatched ')'\n");
413
 
    pout("Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n");
414
 
    return 1;
415
 
  }
416
 
  return 0;
 
377
// Wrapper class for regex(3)
 
378
 
 
379
regular_expression::regular_expression()
 
380
: m_flags(0)
 
381
{
 
382
  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
 
383
}
 
384
 
 
385
regular_expression::regular_expression(const char * pattern, int flags)
 
386
{
 
387
  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
 
388
  compile(pattern, flags);
 
389
}
 
390
 
 
391
regular_expression::~regular_expression()
 
392
{
 
393
  free_buf();
 
394
}
 
395
 
 
396
regular_expression::regular_expression(const regular_expression & x)
 
397
{
 
398
  memset(&m_regex_buf, 0, sizeof(m_regex_buf));
 
399
  copy(x);
 
400
}
 
401
 
 
402
regular_expression & regular_expression::operator=(const regular_expression & x)
 
403
{
 
404
  free_buf();
 
405
  copy(x);
 
406
  return *this;
 
407
}
 
408
 
 
409
void regular_expression::free_buf()
 
410
{
 
411
  if (nonempty(&m_regex_buf, sizeof(m_regex_buf))) {
 
412
    regfree(&m_regex_buf);
 
413
    memset(&m_regex_buf, 0, sizeof(m_regex_buf));
 
414
  }
 
415
}
 
416
 
 
417
void regular_expression::copy(const regular_expression & x)
 
418
{
 
419
  m_pattern = x.m_pattern;
 
420
  m_flags = x.m_flags;
 
421
  m_errmsg = x.m_errmsg;
 
422
 
 
423
  if (!m_pattern.empty() && m_errmsg.empty()) {
 
424
    // There is no POSIX compiled-regex-copy command.
 
425
    if (!compile())
 
426
      throw std::runtime_error(strprintf(
 
427
        "Unable to recompile regular expression \"%s\": %s",
 
428
        m_pattern.c_str(), m_errmsg.c_str()));
 
429
  }
 
430
}
 
431
 
 
432
bool regular_expression::compile(const char * pattern, int flags)
 
433
{
 
434
  free_buf();
 
435
  m_pattern = pattern;
 
436
  m_flags = flags;
 
437
  return compile();
 
438
}
 
439
 
 
440
bool regular_expression::compile()
 
441
{
 
442
  int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), m_flags);
 
443
  if (errcode) {
 
444
    char errmsg[512];
 
445
    regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg));
 
446
    m_errmsg = errmsg;
 
447
    free_buf();
 
448
    return false;
 
449
  }
 
450
 
 
451
  if (check_regex_nesting(m_pattern.c_str()) < 0) {
 
452
    m_errmsg = "Unmatched ')'";
 
453
    free_buf();
 
454
    return false;
 
455
  }
 
456
 
 
457
  m_errmsg.clear();
 
458
  return true;
417
459
}
418
460
 
419
461
// Splits an argument to the -r option into a name part and an (optional) 
465
507
}
466
508
 
467
509
#ifndef HAVE_STRTOULL
468
 
// Replacement for missing strtoull() (Linux with libc < 6, MSVC 6.0)
469
 
// Functionality reduced to split_selective_arg()'s requirements.
 
510
// Replacement for missing strtoull() (Linux with libc < 6, MSVC)
 
511
// Functionality reduced to requirements of smartd and split_selective_arg().
470
512
 
471
 
static uint64_t strtoull(const char * p, char * * endp, int base)
 
513
uint64_t strtoull(const char * p, char * * endp, int base)
472
514
{
473
515
  uint64_t result, maxres;
474
516
  int i = 0;
475
517
  char c = p[i++];
476
 
  // assume base == 0
477
 
  if (c == '0') {
478
 
    if (p[i] == 'x' || p[i] == 'X') {
479
 
      base = 16; i++;
 
518
 
 
519
  if (!base) {
 
520
    if (c == '0') {
 
521
      if (p[i] == 'x' || p[i] == 'X') {
 
522
        base = 16; i++;
 
523
      }
 
524
      else
 
525
        base = 8;
 
526
      c = p[i++];
480
527
    }
481
528
    else
482
 
      base = 8;
483
 
    c = p[i++];
 
529
      base = 10;
484
530
  }
485
 
  else
486
 
    base = 10;
487
531
 
488
532
  result = 0;
489
533
  maxres = ~(uint64_t)0 / (unsigned)base;
507
551
    result = result * (unsigned)base + digit;
508
552
    c = p[i++];
509
553
  }
510
 
  *endp = (char *)p + i - 1;
 
554
  if (endp)
 
555
    *endp = (char *)p + i - 1;
511
556
  return result;
512
557
}
513
558
#endif // HAVE_STRTOLL
565
610
  return 0;
566
611
}
567
612
 
 
613
#ifdef OLD_INTERFACE
 
614
 
 
615
// smartd exit codes
 
616
#define EXIT_NOMEM     8   // out of memory
 
617
#define EXIT_BADCODE   10  // internal error - should NEVER happen
 
618
 
568
619
int64_t bytes = 0;
 
620
 
569
621
// Helps debugging.  If the second argument is non-negative, then
570
622
// decrement bytes by that amount.  Else decrement bytes by (one plus)
571
623
// length of null terminated string.
634
686
  return tmp;
635
687
}
636
688
 
637
 
// Returns nonzero if region of memory contains non-zero entries
638
 
int nonempty(unsigned char *testarea,int n){
639
 
  int i;
640
 
  for (i=0;i<n;i++)
641
 
    if (testarea[i])
642
 
      return 1;
643
 
  return 0;
 
689
#endif // OLD_INTERFACE
 
690
 
 
691
 
 
692
// Returns true if region of memory contains non-zero entries
 
693
bool nonempty(const void * data, int size)
 
694
{
 
695
  for (int i = 0; i < size; i++)
 
696
    if (((const unsigned char *)data)[i])
 
697
      return true;
 
698
  return false;
644
699
}
645
700
 
646
701
 
672
727
  return;
673
728
}
674
729
 
 
730
// return (v)sprintf() formatted std::string
 
731
 
 
732
std::string vstrprintf(const char * fmt, va_list ap)
 
733
{
 
734
  char buf[512];
 
735
  vsnprintf(buf, sizeof(buf), fmt, ap);
 
736
  buf[sizeof(buf)-1] = 0;
 
737
  return buf;
 
738
}
 
739
 
 
740
std::string strprintf(const char * fmt, ...)
 
741
{
 
742
  va_list ap; va_start(ap, fmt);
 
743
  std::string str = vstrprintf(fmt, ap);
 
744
  va_end(ap);
 
745
  return str;
 
746
}
 
747
 
675
748
 
676
749
#ifndef HAVE_WORKING_SNPRINTF
677
750
// Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL),
705
778
}
706
779
 
707
780
#endif
 
781