Back to index

lshw  02.16
osutils.cc
Go to the documentation of this file.
00001 #include "version.h"
00002 #include "osutils.h"
00003 #include <sstream>
00004 #include <iomanip>
00005 #include <stack>
00006 #include <fcntl.h>
00007 #include <sys/stat.h>
00008 #include <unistd.h>
00009 #include <dirent.h>
00010 #include <limits.h>
00011 #include <stdlib.h>
00012 #include <string.h>
00013 #include <regex.h>
00014 #include <ctype.h>
00015 #include <stdio.h>
00016 #include <errno.h>
00017 #include <wchar.h>
00018 #include <sys/utsname.h>
00019 #ifndef MINOR
00020 #include <linux/kdev_t.h>
00021 #endif
00022 
00023 __ID("@(#) $Id: osutils.cc 2433 2012-01-10 22:01:30Z lyonel $");
00024 
00025 using namespace std;
00026 
00027 static stack < string > dirs;
00028 
00029 bool pushd(const string & dir)
00030 {
00031   string curdir = pwd();
00032 
00033   if (dir == "")
00034   {
00035     if (dirs.size() == 0)
00036       return true;
00037 
00038     if (chdir(dirs.top().c_str()) == 0)
00039     {
00040       dirs.pop();
00041       dirs.push(curdir);
00042       return true;
00043     }
00044     else
00045       return false;
00046   }
00047 
00048   if (chdir(dir.c_str()) == 0)
00049   {
00050     dirs.push(curdir);
00051     return true;
00052   }
00053   else
00054     return false;
00055 }
00056 
00057 
00058 string popd()
00059 {
00060   string curdir = pwd();
00061 
00062   if (dirs.size() == 0)
00063     return curdir;
00064 
00065   if (chdir(dirs.top().c_str()) == 0)
00066     dirs.pop();
00067 
00068   return curdir;
00069 }
00070 
00071 
00072 string pwd()
00073 {
00074   char curdir[PATH_MAX + 1];
00075 
00076   if (getcwd(curdir, sizeof(curdir)))
00077     return string(curdir);
00078   else
00079     return "";
00080 }
00081 
00082 
00083 size_t splitlines(const string & s,
00084 vector < string > &lines,
00085 char separator)
00086 {
00087   size_t i = 0, j = 0;
00088   size_t count = 0;
00089 
00090   lines.clear();
00091 
00092   while ((j < s.length()) && ((i = s.find(separator, j)) != string::npos))
00093   {
00094     lines.push_back(s.substr(j, i - j));
00095     count++;
00096     i++;
00097     j = i;
00098   }
00099   if (j < s.length())
00100   {
00101     lines.push_back(s.substr(j));
00102     count++;
00103   }
00104 
00105   return count;
00106 }
00107 
00108 
00109 bool exists(const string & path)
00110 {
00111   return access(path.c_str(), F_OK) == 0;
00112 }
00113 
00114 
00115 bool loadfile(const string & file,
00116 vector < string > &list)
00117 {
00118   char buffer[1024];
00119   string buffer_str = "";
00120   size_t count = 0;
00121   int fd = open(file.c_str(), O_RDONLY);
00122 
00123   if (fd < 0)
00124     return false;
00125 
00126   while ((count = read(fd, buffer, sizeof(buffer))) > 0)
00127     buffer_str += string(buffer, count);
00128 
00129   splitlines(buffer_str, list);
00130 
00131   close(fd);
00132 
00133   return true;
00134 }
00135 
00136 
00137 string get_string(const string & path,
00138 const string & def)
00139 {
00140   int fd = open(path.c_str(), O_RDONLY);
00141   string result = def;
00142 
00143   if (fd >= 0)
00144   {
00145     char buffer[1024];
00146     size_t count = 0;
00147 
00148     memset(buffer, 0, sizeof(buffer));
00149     result = "";
00150 
00151     while ((count = read(fd, buffer, sizeof(buffer))) > 0)
00152       result += string(buffer, count);
00153 
00154     close(fd);
00155   }
00156 
00157   return result;
00158 }
00159 
00160 long get_number(const string & path, long def)
00161 {
00162   string s = get_string(path, "");
00163 
00164   if(s=="") return def;
00165 
00166   return strtol(s.c_str(), NULL, 10);
00167 }
00168 
00169 int selectdir(const struct dirent *d)
00170 {
00171   struct stat buf;
00172 
00173   if (d->d_name[0] == '.')
00174     return 0;
00175 
00176   if (lstat(d->d_name, &buf) != 0)
00177     return 0;
00178 
00179   return S_ISDIR(buf.st_mode);
00180 }
00181 
00182 
00183 int selectlink(const struct dirent *d)
00184 {
00185   struct stat buf;
00186 
00187   if (d->d_name[0] == '.')
00188     return 0;
00189 
00190   if (lstat(d->d_name, &buf) != 0)
00191     return 0;
00192 
00193   return S_ISLNK(buf.st_mode);
00194 }
00195 
00196 int selectfile(const struct dirent *d)
00197 {
00198   struct stat buf;
00199 
00200   if (d->d_name[0] == '.')
00201     return 0;
00202 
00203   if (lstat(d->d_name, &buf) != 0)
00204     return 0;
00205 
00206   return S_ISREG(buf.st_mode);
00207 }
00208 
00209 static int selectdevice(const struct dirent *d)
00210 {
00211   struct stat buf;
00212 
00213   if (d->d_name[0] == '.')
00214     return 0;
00215 
00216   if (lstat(d->d_name, &buf) != 0)
00217     return 0;
00218 
00219   return S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode);
00220 }
00221 
00222 
00223 static bool matches(string name,
00224 mode_t mode,
00225 dev_t device)
00226 {
00227   struct stat buf;
00228 
00229   if (lstat(name.c_str(), &buf) != 0)
00230     return false;
00231 
00232   return ((S_ISCHR(buf.st_mode) && S_ISCHR(mode)) ||
00233     (S_ISBLK(buf.st_mode) && S_ISBLK(mode))) && (buf.st_dev == device);
00234 }
00235 
00236 
00237 static string find_deventry(string basepath,
00238 mode_t mode,
00239 dev_t device)
00240 {
00241   struct dirent **namelist;
00242   int n, i;
00243   string result = "";
00244 
00245   pushd(basepath);
00246 
00247   n = scandir(".", &namelist, selectdevice, alphasort);
00248 
00249   if (n < 0)
00250   {
00251     popd();
00252     return "";
00253   }
00254 
00255   for (i = 0; i < n; i++)
00256   {
00257     if (result == "" && matches(namelist[i]->d_name, mode, device))
00258       result = string(namelist[i]->d_name);
00259     free(namelist[i]);
00260   }
00261   free(namelist);
00262 
00263   popd();
00264 
00265   if (result != "")
00266     return basepath + "/" + result;
00267 
00268   pushd(basepath);
00269   n = scandir(".", &namelist, selectdir, alphasort);
00270   popd();
00271 
00272   if (n < 0)
00273     return "";
00274 
00275   for (i = 0; i < n; i++)
00276   {
00277     if (result == "")
00278       result =
00279         find_deventry(basepath + "/" + string(namelist[i]->d_name), mode,
00280         device);
00281     free(namelist[i]);
00282   }
00283   free(namelist);
00284 
00285   return result;
00286 }
00287 
00288 
00289 string find_deventry(mode_t mode,
00290 dev_t device)
00291 {
00292   return find_deventry("/dev", mode, device);
00293 }
00294 
00295 
00296 string get_devid(const string & name)
00297 {
00298   struct stat buf;
00299 
00300   if((stat(name.c_str(), &buf)==0) && (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)))
00301   {
00302     char devid[80];
00303 
00304     snprintf(devid, sizeof(devid), "%u:%u", (unsigned int)MAJOR(buf.st_rdev), (unsigned int)MINOR(buf.st_rdev));
00305     return string(devid);
00306   }
00307   else
00308     return "";
00309 }
00310 
00311 
00312 bool samefile(const string & path1, const string & path2)
00313 {
00314   struct stat stat1;
00315   struct stat stat2;
00316 
00317   if (stat(path1.c_str(), &stat1) != 0)
00318     return false;
00319   if (stat(path2.c_str(), &stat2) != 0)
00320     return false;
00321 
00322   return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
00323 }
00324 
00325 
00326 string uppercase(const string & s)
00327 {
00328   string result;
00329 
00330   for (unsigned int i = 0; i < s.length(); i++)
00331     result += toupper(s[i]);
00332 
00333   return result;
00334 }
00335 
00336 
00337 string lowercase(const string & s)
00338 {
00339   string result;
00340 
00341   for (unsigned int i = 0; i < s.length(); i++)
00342     result += tolower(s[i]);
00343 
00344   return result;
00345 }
00346 
00347 
00348 string tostring(unsigned long long n)
00349 {
00350   char buffer[80];
00351 
00352   snprintf(buffer, sizeof(buffer), "%lld", n);
00353 
00354   return string(buffer);
00355 }
00356 
00357 
00358 string tohex(unsigned long long n)
00359 {
00360   char buffer[80];
00361 
00362   snprintf(buffer, sizeof(buffer), "%llX", n);
00363 
00364   return string(buffer);
00365 }
00366 
00367 string join(const string & j, const string & s1, const string & s2)
00368 {
00369   if(s1 == "") return s2;
00370   if(s2 == "") return s1;
00371 
00372   return s1 + j + s2;
00373 }
00374 
00375 
00376 bool matches(const string & s, const string & pattern, int cflags)
00377 {
00378   regex_t r;
00379   bool result = false;
00380 
00381   if(regcomp(&r, pattern.c_str(), REG_EXTENDED | REG_NOSUB | cflags) != 0)
00382     return false;
00383 
00384   result = (regexec(&r, s.c_str(), 0, NULL, 0) == 0);
00385 
00386   regfree(&r);
00387 
00388   return result;
00389 }
00390 
00391 
00392 string readlink(const string & path)
00393 {
00394   char buffer[PATH_MAX+1];
00395 
00396   memset(buffer, 0, sizeof(buffer));
00397   if(readlink(path.c_str(), buffer, sizeof(buffer)-1)>0)
00398     return string(buffer);
00399   else
00400     return path;
00401 }
00402 
00403 
00404 string realpath(const string & path)
00405 {
00406   char buffer[PATH_MAX+1];
00407 
00408   memset(buffer, 0, sizeof(buffer));
00409   if(realpath(path.c_str(), buffer))
00410     return string(buffer);
00411   else
00412     return path;
00413 }
00414 
00415 
00416 string spaces(unsigned int count, const string & space)
00417 {
00418   string result = "";
00419   while (count-- > 0)
00420     result += space;
00421 
00422   return result;
00423 }
00424 
00425 string escape(const string & s)
00426 {
00427   string result = "";
00428 
00429   for (unsigned int i = 0; i < s.length(); i++)
00430     // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
00431     if (s[i] == 0x9
00432         || s[i] == 0xA
00433         || s[i] == 0xD
00434         || s[i] >= 0x20)
00435       switch (s[i])
00436       {
00437         case '<':
00438           result += "&lt;";
00439           break;
00440         case '>':
00441           result += "&gt;";
00442           break;
00443         case '&':
00444           result += "&amp;";
00445           break;
00446         case '"':
00447           result += "&quot;";
00448           break;
00449       default:
00450         result += s[i];
00451     }
00452 
00453   return result;
00454 }
00455 
00456 string escapeJSON(const string & s)
00457 {
00458   string result = "";
00459 
00460   for (unsigned int i = 0; i < s.length(); i++)
00461     switch (s[i])
00462     {
00463       case '\r':
00464         result += "\\r";
00465         break;
00466       case '\n':
00467         result += "\\n";
00468         break;
00469       case '\t':
00470         result += "\\t";
00471         break;
00472       case '"':
00473         result += "\\\"";
00474         break;
00475     default:
00476       result += s[i];
00477   }
00478 
00479   return result;
00480 }
00481 
00482 string escapecomment(const string & s)
00483 {
00484   string result = "";
00485   char previous = 0;
00486 
00487   for (unsigned int i = 0; i < s.length(); i++)
00488     if(!(previous == '-' && s[i] == '-'))
00489     {
00490       result += s[i];
00491       previous = s[i];
00492     }
00493 
00494   return result;
00495 }
00496 
00497 unsigned short be_short(const void * from)
00498 {
00499   __uint8_t *p = (__uint8_t*)from;
00500 
00501   return ((__uint16_t)(p[0]) << 8) +
00502     (__uint16_t)p[1];
00503 }
00504 
00505 
00506 unsigned short le_short(const void * from)
00507 {
00508   __uint8_t *p = (__uint8_t*)from;
00509 
00510   return ((__uint16_t)(p[1]) << 8) +
00511     (__uint16_t)p[0];
00512 }
00513 
00514 
00515 unsigned long be_long(const void * from)
00516 {
00517   __uint8_t *p = (__uint8_t*)from;
00518 
00519   return ((__uint32_t)(p[0]) << 24) +
00520     ((__uint32_t)(p[1]) << 16) +
00521     ((__uint32_t)(p[2]) << 8) +
00522     (__uint32_t)p[3];
00523 }
00524 
00525 
00526 unsigned long le_long(const void * from)
00527 {
00528   __uint8_t *p = (__uint8_t*)from;
00529 
00530   return ((__uint32_t)(p[3]) << 24) +
00531     ((__uint32_t)(p[2]) << 16) +
00532     ((__uint32_t)(p[1]) << 8) +
00533     (__uint32_t)p[0];
00534 
00535 }
00536 
00537 
00538 unsigned long long be_longlong(const void * from)
00539 {
00540   __uint8_t *p = (__uint8_t*)from;
00541 
00542   return ((unsigned long long)(p[0]) << 56) +
00543     ((unsigned long long)(p[1]) << 48) +
00544     ((unsigned long long)(p[2]) << 40) +
00545     ((unsigned long long)(p[3]) << 32) +
00546     ((unsigned long long)(p[4]) << 24) +
00547     ((unsigned long long)(p[5]) << 16) +
00548     ((unsigned long long)(p[6]) << 8) +
00549     (unsigned long long)p[7];
00550 }
00551 
00552 
00553 unsigned long long le_longlong(const void * from)
00554 {
00555   __uint8_t *p = (__uint8_t*)from;
00556 
00557   return ((unsigned long long)(p[7]) << 56) +
00558     ((unsigned long long)(p[6]) << 48) +
00559     ((unsigned long long)(p[5]) << 40) +
00560     ((unsigned long long)(p[4]) << 32) +
00561     ((unsigned long long)(p[3]) << 24) +
00562     ((unsigned long long)(p[2]) << 16) +
00563     ((unsigned long long)(p[1]) << 8) +
00564     (unsigned long long)p[0];
00565 }
00566 
00567 
00568 int open_dev(dev_t dev, const string & name)
00569 {
00570   static const char *paths[] =
00571   {
00572     "/usr/tmp", "/var/tmp", "/var/run", "/dev", "/tmp", NULL
00573   };
00574   char const **p;
00575   char fn[64];
00576   int fd;
00577 
00578   for (p = paths; *p; p++)
00579   {
00580     if(name=="")
00581       snprintf(fn, sizeof(fn), "%s/lshw-%d", *p, getpid());
00582     else
00583       snprintf(fn, sizeof(fn), "%s", name.c_str());
00584     if ((mknod(fn, (S_IFCHR | S_IREAD), dev) == 0) || (errno == EEXIST))
00585     {
00586       fd = open(fn, O_RDONLY);
00587       if(name=="") unlink(fn);
00588       if (fd >= 0)
00589         return fd;
00590     }
00591   }
00592   return -1;
00593 }                                                 /* open_dev */
00594 
00595 #define putchar(c) ((char)((c) & 0xff))
00596 
00597 string utf8(wchar_t c)
00598 {
00599   string result = "";
00600 
00601   if (c < 0x80)
00602   {
00603     result += putchar (c);
00604   }
00605   else if (c < 0x800)
00606   {
00607     result += putchar (0xC0 | c>>6);
00608     result += putchar (0x80 | (c & 0x3F));
00609   }
00610   else if (c < 0x10000)
00611   {
00612     result += putchar (0xE0 | c>>12);
00613     result += putchar (0x80 | (c>>6 & 0x3F));
00614     result += putchar (0x80 | (c & 0x3F));
00615   }
00616   else if (c < 0x200000)
00617   {
00618     result += putchar (0xF0 | c>>18);
00619     result += putchar (0x80 | (c>>12 & 0x3F));
00620     result += putchar (0x80 | (c>>6 & 0x3F));
00621     result += putchar (0x80 | (c & 0x3F));
00622   }
00623 
00624   return result;
00625 }
00626 
00627 string utf8(uint16_t * s, ssize_t length, bool forcelittleendian)
00628 {
00629   string result = "";
00630   ssize_t i;
00631 
00632   for(i=0; (length<0) || (i<length); i++)
00633     if(s[i])
00634       result += utf8(forcelittleendian?le_short(s+i):s[i]);
00635     else
00636       break;  // NUL found
00637 
00638   return result;
00639 }
00640 
00641 // U+FFFD replacement character
00642 #define REPLACEMENT  "\357\277\275"
00643 
00644 string utf8_sanitize(const string & s)
00645 {
00646   unsigned int i = 0;
00647   unsigned int remaining = 0;
00648   string result = "";
00649   string emit = "";
00650   unsigned char c = 0;
00651 
00652   while(i<s.length())
00653   {
00654     c = s[i];
00655     switch(remaining)
00656     {
00657       case 3:
00658       case 2:
00659       case 1:
00660         if((0x80<=c) && (c<=0xbf))
00661         {
00662           emit += s[i];
00663           remaining--;
00664         }
00665         else         // invalid sequence (truncated)
00666         {
00667           emit = REPLACEMENT;
00668           emit += s[i];
00669           remaining = 0;
00670         }
00671         break;
00672 
00673       case 0:
00674         result += emit;
00675         emit = "";
00676 
00677         if(c<=0x7f)
00678           emit = s[i];
00679         else
00680         if((0xc2<=c) && (c<=0xdf)) // start 2-byte sequence
00681         {
00682           remaining = 1;
00683           emit = s[i];
00684         }
00685         else
00686         if((0xe0<=c) && (c<=0xef)) // start 3-byte sequence
00687         {
00688           remaining = 2;
00689           emit = s[i];
00690         }
00691         else
00692         if((0xf0<=c) && (c<=0xf4)) // start 4-byte sequence
00693         {
00694           remaining = 3;
00695           emit = s[i];
00696         }
00697         else
00698           emit = REPLACEMENT;      // invalid character
00699 
00700         break;
00701     }
00702 
00703     i++;
00704   }
00705 
00706   if(remaining == 0)
00707     result += emit;
00708 
00709   return result;
00710 }
00711 
00712 string decimalkilos(unsigned long long value)
00713 {
00714   const char *prefixes = "KMGTPEZY";
00715   unsigned int i = 0;
00716   ostringstream out;
00717 
00718   while ((i <= strlen(prefixes)) && ((value > 10000) || (value % 1000 == 0)))
00719   {
00720     value = value / 1000;
00721     i++;
00722   }
00723 
00724   out << value;
00725   if ((i > 0) && (i <= strlen(prefixes)))
00726     out << prefixes[i - 1];
00727 
00728   return out.str();
00729 }
00730 
00731 
00732 string kilobytes(unsigned long long value)
00733 {
00734   const char *prefixes = "KMGTPEZY";
00735   unsigned int i = 0;
00736   ostringstream out;
00737 
00738   while ((i <= strlen(prefixes)) && ((value > 10240) || (value % 1024 == 0)))
00739   {
00740     value = value >> 10;
00741     i++;
00742   }
00743 
00744   out << value;
00745   if ((i > 0) && (i <= strlen(prefixes)))
00746     out << prefixes[i - 1];
00747   out << "iB";
00748 
00749   return out.str();
00750 }
00751 
00752 string operating_system()
00753 {
00754   vector<string> osinfo;
00755   struct utsname u;
00756   string os = "";
00757 
00758   if(loadfile("/etc/lsb-release", osinfo))
00759     os = osinfo[0];
00760   else if(loadfile("/etc/lsb_release", osinfo))
00761     os = osinfo[0];
00762   else if(loadfile("/etc/system-release", osinfo))
00763     os = osinfo[0];
00764   else if(loadfile("/etc/release", osinfo))
00765     os = osinfo[0];
00766   else if(loadfile("/etc/arch-release", osinfo))
00767     os = osinfo[0];
00768   else if(loadfile("/etc/arklinux-release", osinfo))
00769     os = osinfo[0];
00770   else if(loadfile("/etc/aurox-release", osinfo))
00771     os = osinfo[0];
00772   else if(loadfile("/etc/conectiva-release", osinfo))
00773     os = osinfo[0];
00774   else if(loadfile("/etc/debian_version", osinfo))
00775     os = osinfo[0];
00776   else if(loadfile("/etc/fedora-release", osinfo))
00777     os = osinfo[0];
00778   else if(loadfile("/etc/gentoo-release", osinfo))
00779     os = osinfo[0];
00780   else if(loadfile("/etc/linuxppc-release", osinfo))
00781     os = osinfo[0];
00782   else if(loadfile("/etc/mandrake-release", osinfo))
00783     os = osinfo[0];
00784   else if(loadfile("/etc/mandriva-release", osinfo))
00785     os = osinfo[0];
00786   else if(loadfile("/etc/novell-release", osinfo))
00787     os = osinfo[0];
00788   else if(loadfile("/etc/pld-release", osinfo))
00789     os = osinfo[0];
00790   else if(loadfile("/etc/redhat-release", osinfo))
00791     os = osinfo[0];
00792   else if(loadfile("/etc/slackware-version", osinfo))
00793     os = osinfo[0];
00794   else if(loadfile("/etc/sun-release", osinfo))
00795     os = osinfo[0];
00796   else if(loadfile("/etc/SuSE-release", osinfo))
00797     os = osinfo[0];
00798   else if(loadfile("/etc/yellowdog-release", osinfo))
00799     os = osinfo[0];
00800 
00801   if(uname(&u) != 0) return "";
00802 
00803   os += (os == ""?"":" ; ") + string(u.sysname)+" "+string(u.release);
00804 
00805 #if defined(__GLIBC__) && defined(_CS_GNU_LIBC_VERSION)
00806   char version[PATH_MAX];
00807 
00808       if(confstr(_CS_GNU_LIBC_VERSION, version, sizeof(version))>0)
00809         os += " ; "+string(version);
00810 #endif
00811 
00812   return os;
00813 }
00814 
00815 string platform()
00816 {
00817   string p = "";
00818   struct utsname u;
00819 
00820 #ifdef __i386__
00821   p = "i386";
00822 #endif
00823 
00824   if(uname(&u) != 0)
00825     return p;
00826   else
00827     return p + (p!=""?"/":"") + string(u.machine);
00828 }