/ src / core / osutils.cc
osutils.cc
  1  #include "version.h"
  2  #include "osutils.h"
  3  #include <sstream>
  4  #include <iomanip>
  5  #include <stack>
  6  #include <cstring>
  7  #include <fcntl.h>
  8  #include <sys/stat.h>
  9  #include <unistd.h>
 10  #include <dirent.h>
 11  #include <limits.h>
 12  #include <stdlib.h>
 13  #include <stdint.h>
 14  #include <string.h>
 15  #include <libgen.h>
 16  #include <regex.h>
 17  #include <ctype.h>
 18  #include <stdio.h>
 19  #include <errno.h>
 20  #include <wchar.h>
 21  #include <sys/utsname.h>
 22  #ifndef MINOR
 23  #include <linux/kdev_t.h>
 24  #endif
 25  #ifdef ZLIB
 26  #include <zlib.h>
 27  #endif
 28  
 29  __ID("@(#) $Id$");
 30  
 31  using namespace std;
 32  
 33  static stack < string > dirs;
 34  
 35  bool pushd(const string & dir)
 36  {
 37    string curdir = pwd();
 38  
 39    if (dir == "")
 40    {
 41      if (dirs.size() == 0)
 42        return true;
 43  
 44      if (chdir(dirs.top().c_str()) == 0)
 45      {
 46        dirs.pop();
 47        dirs.push(curdir);
 48        return true;
 49      }
 50      else
 51        return false;
 52    }
 53  
 54    if (chdir(dir.c_str()) == 0)
 55    {
 56      dirs.push(curdir);
 57      return true;
 58    }
 59    else
 60      return false;
 61  }
 62  
 63  
 64  string popd()
 65  {
 66    string curdir = pwd();
 67  
 68    if (dirs.size() == 0)
 69      return curdir;
 70  
 71    if (chdir(dirs.top().c_str()) == 0)
 72      dirs.pop();
 73  
 74    return curdir;
 75  }
 76  
 77  
 78  string pwd()
 79  {
 80    char curdir[PATH_MAX + 1];
 81  
 82    if (getcwd(curdir, sizeof(curdir)))
 83      return string(curdir);
 84    else
 85      return "";
 86  }
 87  
 88  
 89  size_t splitlines(const string & s,
 90  vector < string > &lines,
 91  char separator)
 92  {
 93    size_t i = 0, j = 0;
 94    size_t count = 0;
 95  
 96    lines.clear();
 97  
 98    while ((j < s.length()) && ((i = s.find(separator, j)) != string::npos))
 99    {
100      lines.push_back(s.substr(j, i - j));
101      count++;
102      i++;
103      j = i;
104    }
105    if (j < s.length())
106    {
107      lines.push_back(s.substr(j));
108      count++;
109    }
110  
111    return count;
112  }
113  
114  
115  bool exists(const string & path)
116  {
117    return access(path.c_str(), F_OK) == 0;
118  }
119  
120  
121  #ifdef ZLIB
122  
123  typedef gzFile data_file;
124  static data_file file_open(const string & file)
125  {
126    data_file result = gzopen((file + ".gz").c_str(), "rb");
127    if (!result)
128    {
129      result = gzopen(file.c_str(), "rb");
130    }
131    return result;
132  }
133  #define file_open_error(f) ((f) == NULL)
134  #define file_read(f, b, l) gzread((f), (b), (l))
135  #define file_close(f) gzclose(f)
136  
137  #else
138  
139  typedef int data_file;
140  #define file_open(f) open((f).c_str(), O_RDONLY);
141  #define file_open_error(f) ((f) < 0)
142  #define file_read(f, b, l) read((f), (b), (l))
143  #define file_close(f) close(f)
144  
145  #endif
146  
147  bool loadfile(const string & file,
148  vector < string > &list)
149  {
150    char buffer[1024];
151    string buffer_str = "";
152    ssize_t count = 0;
153    data_file fd = file_open(file);
154  
155    if (file_open_error(fd))
156      return false;
157  
158    while ((count = file_read(fd, buffer, sizeof(buffer))) > 0)
159      buffer_str += string(buffer, count);
160  
161    splitlines(buffer_str, list);
162  
163    file_close(fd);
164  
165    return true;
166  }
167  
168  
169  string get_string(const string & path,
170  const string & def)
171  {
172    int fd = open(path.c_str(), O_RDONLY);
173    string result = def;
174  
175    if (fd >= 0)
176    {
177      char buffer[1024];
178      ssize_t count = 0;
179  
180      memset(buffer, 0, sizeof(buffer));
181      result = "";
182  
183      while ((count = read(fd, buffer, sizeof(buffer))) > 0)
184        result += string(buffer, count);
185  
186      close(fd);
187    }
188  
189    return result;
190  }
191  
192  long get_number(const string & path, long def)
193  {
194    string s = get_string(path, "");
195  
196    if(s=="") return def;
197  
198    return strtol(s.c_str(), NULL, 10);
199  }
200  
201  int selectdir(const struct dirent *d)
202  {
203    struct stat buf;
204  
205    if (d->d_name[0] == '.')
206      return 0;
207  
208    if (lstat(d->d_name, &buf) != 0)
209      return 0;
210  
211    return S_ISDIR(buf.st_mode);
212  }
213  
214  
215  int selectlink(const struct dirent *d)
216  {
217    struct stat buf;
218  
219    if (d->d_name[0] == '.')
220      return 0;
221  
222    if (lstat(d->d_name, &buf) != 0)
223      return 0;
224  
225    return S_ISLNK(buf.st_mode);
226  }
227  
228  int selectfile(const struct dirent *d)
229  {
230    struct stat buf;
231  
232    if (d->d_name[0] == '.')
233      return 0;
234  
235    if (lstat(d->d_name, &buf) != 0)
236      return 0;
237  
238    return S_ISREG(buf.st_mode);
239  }
240  
241  static int selectdevice(const struct dirent *d)
242  {
243    struct stat buf;
244  
245    if (d->d_name[0] == '.')
246      return 0;
247  
248    if (lstat(d->d_name, &buf) != 0)
249      return 0;
250  
251    return S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode);
252  }
253  
254  
255  static bool matches(string name,
256  mode_t mode,
257  dev_t device)
258  {
259    struct stat buf;
260  
261    if (lstat(name.c_str(), &buf) != 0)
262      return false;
263  
264    return ((S_ISCHR(buf.st_mode) && S_ISCHR(mode)) ||
265      (S_ISBLK(buf.st_mode) && S_ISBLK(mode))) && (buf.st_dev == device);
266  }
267  
268  
269  static string find_deventry(string basepath,
270  mode_t mode,
271  dev_t device)
272  {
273    struct dirent **namelist;
274    int n, i;
275    string result = "";
276  
277    pushd(basepath);
278  
279    n = scandir(".", &namelist, selectdevice, alphasort);
280  
281    if (n < 0)
282    {
283      popd();
284      return "";
285    }
286  
287    for (i = 0; i < n; i++)
288    {
289      if (result == "" && matches(namelist[i]->d_name, mode, device))
290        result = string(namelist[i]->d_name);
291      free(namelist[i]);
292    }
293    free(namelist);
294  
295    popd();
296  
297    if (result != "")
298      return basepath + "/" + result;
299  
300    pushd(basepath);
301    n = scandir(".", &namelist, selectdir, alphasort);
302    popd();
303  
304    if (n < 0)
305      return "";
306  
307    for (i = 0; i < n; i++)
308    {
309      if (result == "")
310        result =
311          find_deventry(basepath + "/" + string(namelist[i]->d_name), mode,
312          device);
313      free(namelist[i]);
314    }
315    free(namelist);
316  
317    return result;
318  }
319  
320  
321  string find_deventry(mode_t mode,
322  dev_t device)
323  {
324    return find_deventry("/dev", mode, device);
325  }
326  
327  
328  string get_devid(const string & name)
329  {
330    struct stat buf;
331  
332    if((stat(name.c_str(), &buf)==0) && (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)))
333    {
334      char devid[80];
335  
336      snprintf(devid, sizeof(devid), "%u:%u", (unsigned int)MAJOR(buf.st_rdev), (unsigned int)MINOR(buf.st_rdev));
337      return string(devid);
338    }
339    else
340      return "";
341  }
342  
343  
344  bool samefile(const string & path1, const string & path2)
345  {
346    struct stat stat1;
347    struct stat stat2;
348  
349    if (stat(path1.c_str(), &stat1) != 0)
350      return false;
351    if (stat(path2.c_str(), &stat2) != 0)
352      return false;
353  
354    return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
355  }
356  
357  
358  string uppercase(const string & s)
359  {
360    string result;
361  
362    for (unsigned int i = 0; i < s.length(); i++)
363      result += toupper(s[i]);
364  
365    return result;
366  }
367  
368  
369  string lowercase(const string & s)
370  {
371    string result;
372  
373    for (unsigned int i = 0; i < s.length(); i++)
374      result += tolower(s[i]);
375  
376    return result;
377  }
378  
379  
380  string tostring(unsigned long long n)
381  {
382    char buffer[80];
383  
384    snprintf(buffer, sizeof(buffer), "%lld", n);
385  
386    return string(buffer);
387  }
388  
389  
390  string tohex(unsigned long long n)
391  {
392    char buffer[80];
393  
394    snprintf(buffer, sizeof(buffer), "%llX", n);
395  
396    return string(buffer);
397  }
398  
399  string join(const string & j, const string & s1, const string & s2)
400  {
401    if(s1 == "") return s2;
402    if(s2 == "") return s1;
403  
404    return s1 + j + s2;
405  }
406  
407  
408  bool matches(const string & s, const string & pattern, int cflags)
409  {
410    regex_t r;
411    bool result = false;
412  
413    if(regcomp(&r, pattern.c_str(), REG_EXTENDED | REG_NOSUB | cflags) != 0)
414      return false;
415  
416    result = (regexec(&r, s.c_str(), 0, NULL, 0) == 0);
417  
418    regfree(&r);
419  
420    return result;
421  }
422  
423  
424  string readlink(const string & path)
425  {
426    char buffer[PATH_MAX+1];
427  
428    memset(buffer, 0, sizeof(buffer));
429    if(readlink(path.c_str(), buffer, sizeof(buffer)-1)>0)
430      return string(buffer);
431    else
432      return path;
433  }
434  
435  
436  string realpath(const string & path)
437  {
438    char buffer[PATH_MAX+1];
439  
440    memset(buffer, 0, sizeof(buffer));
441    if(realpath(path.c_str(), buffer))
442      return string(buffer);
443    else
444      return path;
445  }
446  
447  
448  string dirname(const string & path)
449  {
450    size_t len = path.length();
451    char *buffer = new char[len + 1];
452    path.copy(buffer, len);
453    buffer[len] = '\0';
454    string result = dirname(buffer);
455    delete[] buffer;
456    return result;
457  }
458  
459  string shortname(const string & path)
460  {
461    size_t len = path.length();
462    char *buffer = new char[len + 1];
463    path.copy(buffer, len);
464    buffer[len] = '\0';
465    string result = basename(buffer);
466    delete[] buffer;
467    return result;
468  }
469  
470  string spaces(unsigned int count, const string & space)
471  {
472    string result = "";
473    while (count-- > 0)
474      result += space;
475  
476    return result;
477  }
478  
479  string escape(const string & s)
480  {
481    string result = "";
482  
483    for (unsigned int i = 0; i < s.length(); i++)
484      // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
485      if (s[i] == 0x9
486          || s[i] == 0xA
487          || s[i] == 0xD
488          || s[i] >= 0x20)
489        switch (s[i])
490        {
491          case '<':
492            result += "&lt;";
493            break;
494          case '>':
495            result += "&gt;";
496            break;
497          case '&':
498            result += "&amp;";
499            break;
500          case '"':
501            result += "&quot;";
502            break;
503        default:
504          result += s[i];
505      }
506  
507    return result;
508  }
509  
510  string escapeJSON(const string & s)
511  {
512    string result = "";
513  
514    for (unsigned int i = 0; i < s.length(); i++)
515      switch (s[i])
516      {
517        case '\r':
518          result += "\\r";
519          break;
520        case '\n':
521          result += "\\n";
522          break;
523        case '\t':
524          result += "\\t";
525          break;
526        case '"':
527          result += "\\\"";
528          break;
529        case '\\':
530          result += "\\\\";
531          break;
532      default:
533        result += s[i];
534    }
535  
536    return result;
537  }
538  
539  string escapecomment(const string & s)
540  {
541    string result = "";
542    char previous = 0;
543  
544    for (unsigned int i = 0; i < s.length(); i++)
545      if(!(previous == '-' && s[i] == '-'))
546      {
547        result += s[i];
548        previous = s[i];
549      }
550  
551    return result;
552  }
553  
554  unsigned short be_short(const void * from)
555  {
556    uint8_t *p = (uint8_t*)from;
557  
558    return ((uint16_t)(p[0]) << 8) +
559      (uint16_t)p[1];
560  }
561  
562  
563  unsigned short le_short(const void * from)
564  {
565    uint8_t *p = (uint8_t*)from;
566  
567    return ((uint16_t)(p[1]) << 8) +
568      (uint16_t)p[0];
569  }
570  
571  
572  unsigned long be_long(const void * from)
573  {
574    uint8_t *p = (uint8_t*)from;
575  
576    return ((uint32_t)(p[0]) << 24) +
577      ((uint32_t)(p[1]) << 16) +
578      ((uint32_t)(p[2]) << 8) +
579      (uint32_t)p[3];
580  }
581  
582  
583  unsigned long le_long(const void * from)
584  {
585    uint8_t *p = (uint8_t*)from;
586  
587    return ((uint32_t)(p[3]) << 24) +
588      ((uint32_t)(p[2]) << 16) +
589      ((uint32_t)(p[1]) << 8) +
590      (uint32_t)p[0];
591  
592  }
593  
594  
595  unsigned long long be_longlong(const void * from)
596  {
597    uint8_t *p = (uint8_t*)from;
598  
599    return ((unsigned long long)(p[0]) << 56) +
600      ((unsigned long long)(p[1]) << 48) +
601      ((unsigned long long)(p[2]) << 40) +
602      ((unsigned long long)(p[3]) << 32) +
603      ((unsigned long long)(p[4]) << 24) +
604      ((unsigned long long)(p[5]) << 16) +
605      ((unsigned long long)(p[6]) << 8) +
606      (unsigned long long)p[7];
607  }
608  
609  
610  unsigned long long le_longlong(const void * from)
611  {
612    uint8_t *p = (uint8_t*)from;
613  
614    return ((unsigned long long)(p[7]) << 56) +
615      ((unsigned long long)(p[6]) << 48) +
616      ((unsigned long long)(p[5]) << 40) +
617      ((unsigned long long)(p[4]) << 32) +
618      ((unsigned long long)(p[3]) << 24) +
619      ((unsigned long long)(p[2]) << 16) +
620      ((unsigned long long)(p[1]) << 8) +
621      (unsigned long long)p[0];
622  }
623  
624  
625  int open_dev(dev_t dev, int dev_type, const string & name)
626  {
627    static const char *paths[] =
628    {
629      "/usr/tmp", "/var/tmp", "/var/run", "/dev", "/tmp", NULL
630    };
631    char const **p;
632    char fn[64];
633    int fd;
634  
635    for (p = paths; *p; p++)
636    {
637      if(name=="")
638        snprintf(fn, sizeof(fn), "%s/lshw-%d", *p, getpid());
639      else
640        snprintf(fn, sizeof(fn), "%s", name.c_str());
641      if ((mknod(fn, (dev_type | S_IREAD), dev) == 0) || (errno == EEXIST))
642      {
643        fd = open(fn, O_RDONLY);
644        if(name=="") unlink(fn);
645        if (fd >= 0)
646          return fd;
647      }
648    }
649    return -1;
650  }                                                 /* open_dev */
651  
652  #define putchar(c) ((char)((c) & 0xff))
653  
654  string utf8(wchar_t c)
655  {
656    string result = "";
657  
658    if (c < 0x80)
659    {
660      result += putchar (c);
661    }
662    else if (c < 0x800)
663    {
664      result += putchar (0xC0 | c>>6);
665      result += putchar (0x80 | (c & 0x3F));
666    }
667    else if (c < 0x10000)
668    {
669      result += putchar (0xE0 | c>>12);
670      result += putchar (0x80 | (c>>6 & 0x3F));
671      result += putchar (0x80 | (c & 0x3F));
672    }
673    else if (c < 0x200000)
674    {
675      result += putchar (0xF0 | c>>18);
676      result += putchar (0x80 | (c>>12 & 0x3F));
677      result += putchar (0x80 | (c>>6 & 0x3F));
678      result += putchar (0x80 | (c & 0x3F));
679    }
680  
681    return result;
682  }
683  
684  string utf8(uint16_t * s, ssize_t length, bool forcelittleendian)
685  {
686    string result = "";
687    ssize_t i;
688  
689    for(i=0; (length<0) || (i<length); i++)
690      if(s[i])
691        result += utf8(forcelittleendian?le_short(s+i):s[i]);
692      else
693        break;	// NUL found
694  
695    return result;
696  }
697  
698  // U+FFFD replacement character
699  #define REPLACEMENT  "\357\277\275"
700  
701  string utf8_sanitize(const string & s, bool autotruncate)
702  {
703    unsigned int i = 0;
704    unsigned int remaining = 0;
705    string result = "";
706    string emit = "";
707    unsigned char c = 0;
708  
709    while(i<s.length())
710    {
711      c = s[i];
712      switch(remaining)
713      {
714        case 3:
715        case 2:
716        case 1:
717          if((0x80<=c) && (c<=0xbf))
718          {
719            emit += s[i];
720            remaining--;
721          }
722          else		// invalid sequence (truncated)
723          {
724            if(autotruncate) return result;
725            emit = REPLACEMENT;
726            emit += s[i];
727            remaining = 0;
728          }
729          break;
730  
731        case 0:
732          result += emit;
733          emit = "";
734  
735          if(c<=0x7f)
736            emit = s[i];
737          else
738          if((0xc2<=c) && (c<=0xdf))	// start 2-byte sequence
739          {
740            remaining = 1;
741            emit = s[i];
742          }
743          else
744          if((0xe0<=c) && (c<=0xef))	// start 3-byte sequence
745          {
746            remaining = 2;
747            emit = s[i];
748          }
749          else
750          if((0xf0<=c) && (c<=0xf4))	// start 4-byte sequence
751          {
752            remaining = 3;
753            emit = s[i];
754          }
755          else
756          {
757            if(autotruncate) return result;
758            emit = REPLACEMENT;	// invalid character
759          }
760  
761          break;
762      }
763  
764      i++;
765    }
766  
767    if(remaining == 0)
768      result += emit;
769  
770    return result;
771  }
772  
773  string decimalkilos(unsigned long long value)
774  {
775    const char *prefixes = "KMGTPEZY";
776    unsigned int i = 0;
777    ostringstream out;
778  
779    while ((i <= strlen(prefixes)) && ((value > 10000) || (value % 1000 == 0)))
780    {
781      value = value / 1000;
782      i++;
783    }
784  
785    out << value;
786    if ((i > 0) && (i <= strlen(prefixes)))
787      out << prefixes[i - 1];
788  
789    return out.str();
790  }
791  
792  
793  string kilobytes(unsigned long long value)
794  {
795    const char *prefixes = "KMGTPEZY";
796    unsigned int i = 0;
797    ostringstream out;
798  
799    while ((i <= strlen(prefixes)) && ((value > 10240) || (value % 1024 == 0)))
800    {
801      value = value >> 10;
802      i++;
803    }
804  
805    out << value;
806    if ((i > 0) && (i <= strlen(prefixes)))
807      out << prefixes[i - 1];
808    out << "iB";
809  
810    return out.str();
811  }
812  
813  string operating_system()
814  {
815    vector<string> osinfo;
816    struct utsname u;
817    string os = "";
818  
819    if(loadfile("/etc/lsb-release", osinfo) && (osinfo.size() > 0))
820      os = osinfo[0];
821    else if(loadfile("/etc/lsb_release", osinfo) && (osinfo.size() > 0))
822      os = osinfo[0];
823    else if(loadfile("/etc/system-release", osinfo) && (osinfo.size() > 0))
824      os = osinfo[0];
825    else if(loadfile("/etc/release", osinfo) && (osinfo.size() > 0))
826      os = osinfo[0];
827    else if(loadfile("/etc/arch-release", osinfo) && (osinfo.size() > 0))
828      os = osinfo[0];
829    else if(loadfile("/etc/arklinux-release", osinfo) && (osinfo.size() > 0))
830      os = osinfo[0];
831    else if(loadfile("/etc/aurox-release", osinfo) && (osinfo.size() > 0))
832      os = osinfo[0];
833    else if(loadfile("/etc/conectiva-release", osinfo) && (osinfo.size() > 0))
834      os = osinfo[0];
835    else if(loadfile("/etc/debian_version", osinfo) && (osinfo.size() > 0))
836      os = osinfo[0];
837    else if(loadfile("/etc/fedora-release", osinfo) && (osinfo.size() > 0))
838      os = osinfo[0];
839    else if(loadfile("/etc/gentoo-release", osinfo) && (osinfo.size() > 0))
840      os = osinfo[0];
841    else if(loadfile("/etc/linuxppc-release", osinfo) && (osinfo.size() > 0))
842      os = osinfo[0];
843    else if(loadfile("/etc/mandrake-release", osinfo) && (osinfo.size() > 0))
844      os = osinfo[0];
845    else if(loadfile("/etc/mandriva-release", osinfo) && (osinfo.size() > 0))
846      os = osinfo[0];
847    else if(loadfile("/etc/novell-release", osinfo) && (osinfo.size() > 0))
848      os = osinfo[0];
849    else if(loadfile("/etc/pld-release", osinfo) && (osinfo.size() > 0))
850      os = osinfo[0];
851    else if(loadfile("/etc/redhat-release", osinfo) && (osinfo.size() > 0))
852      os = osinfo[0];
853    else if(loadfile("/etc/slackware-version", osinfo) && (osinfo.size() > 0))
854      os = osinfo[0];
855    else if(loadfile("/etc/sun-release", osinfo) && (osinfo.size() > 0))
856      os = osinfo[0];
857    else if(loadfile("/etc/SuSE-release", osinfo) && (osinfo.size() > 0))
858      os = osinfo[0];
859    else if(loadfile("/etc/yellowdog-release", osinfo) && (osinfo.size() > 0))
860      os = osinfo[0];
861  
862    if(uname(&u) != 0) return "";
863  
864    os += (os == ""?"":" ; ") + string(u.sysname)+" "+string(u.release);
865  
866  #if defined(__GLIBC__) && defined(_CS_GNU_LIBC_VERSION)
867    char version[PATH_MAX];
868  
869        if(confstr(_CS_GNU_LIBC_VERSION, version, sizeof(version))>0)
870          os += " ; "+string(version);
871  #endif
872  
873    return os;
874  }
875  
876  string platform()
877  {
878    struct utsname u;
879  
880    if(uname(&u) != 0)
881      return string("i386");
882    else
883      return string(u.machine);
884  }