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 += "<"; 493 break; 494 case '>': 495 result += ">"; 496 break; 497 case '&': 498 result += "&"; 499 break; 500 case '"': 501 result += """; 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 }