Client: improve Linux OS detection

Gathers more information about the Linux OS using lsb_release, /etc/os-release or /etc/redhat-release (in that order) and adds that information to the os_name and os_version fields. This produces information like this:

os_name: Linux CentOS Linux
os_version: 3.10.0-327.18.2.el7.x86_64 (CentOS Linux 7 (Core))

os_name: Linux
os_version: 2.6.32-642.1.1.el6.x86_64 (CentOS release 6.8 (Final))

os_name: Linux Ubuntu
os_version: 3.14.65-68 (Ubuntu 16.04 LTS)
product_name: ODROID-C2

os_name: Linux Debian
os_version: 4.5.0-2-amd64 (Debian GNU/Linux testing (stretch))

This should work on most major distributions and will give a better overview on what Distribution is used by volunteers.
This commit is contained in:
Christian Beer 2016-06-20 08:39:24 +02:00
parent 45bf51fe43
commit ede61a24ea
5 changed files with 175 additions and 1 deletions

View File

@ -1589,6 +1589,124 @@ int HOST_INFO::get_os_info() {
#else
#error Need to specify a method to obtain OS name/version
#endif
#if LINUX_LIKE_SYSTEM
bool found_something = false;
char buf[256],buf2[256];
char dist_pretty[256], dist_name[256], dist_version[256], dist_codename[256];
strcpy(dist_pretty, "");
strcpy(dist_name, "");
strcpy(dist_version, "");
strcpy(dist_codename, "");
// see: http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/lsbrelease.html
// although the output is not clearly specified it seems to be constant
FILE* f = popen("/usr/bin/lsb_release -a 2>&1", "r");
if (f) {
while (fgets(buf, 256, f)) {
strip_whitespace(buf);
if ( strstr(buf, "Description:") ) {
found_something = true;
safe_strcpy(dist_pretty, strchr(buf, ':') + 1);
strip_whitespace(dist_pretty);
}
if ( strstr(buf, "Distributor ID:") ) {
found_something = true;
safe_strcpy(dist_name, strchr(buf, ':') + 1);
strip_whitespace(dist_name);
}
if ( strstr(buf, "Release:") ) {
found_something = true;
safe_strcpy(dist_version, strchr(buf, ':') + 1);
strip_whitespace(dist_version);
}
if ( strstr(buf, "Codename:") ) {
found_something = true;
safe_strcpy(dist_codename, strchr(buf, ':') + 1);
strip_whitespace(dist_codename);
}
}
pclose(f);
}
if (!found_something) {
// see: https://www.freedesktop.org/software/systemd/man/os-release.html
f = fopen("/etc/os-release", "r");
if (f) {
while (fgets(buf, 256, f)) {
strip_whitespace(buf);
// check if substr is at the beginning of the line
if ( strstr(buf, "PRETTY_NAME=") == buf ) {
found_something = true;
safe_strcpy(buf2, strchr(buf, '=') + 1);
strip_quotes(buf2);
safe_strcpy(dist_pretty, buf2);
continue;
}
if ( strstr(buf, "NAME=") == buf ) {
found_something = true;
safe_strcpy(buf2, strchr(buf, '=') + 1);
strip_quotes(buf2);
safe_strcpy(dist_name, buf2);
continue;
}
if ( strstr(buf, "VERSION=") == buf ) {
found_something = true;
safe_strcpy(buf2, strchr(buf, '=') + 1);
strip_quotes(buf2);
safe_strcpy(dist_version, buf2);
continue;
}
// could also be "UBUNTU_CODENAME="
if ( strstr(buf, "CODENAME=") ) {
found_something = true;
safe_strcpy(buf2, strchr(buf, '=') + 1);
strip_quotes(buf2);
safe_strcpy(dist_codename, buf2);
continue;
}
}
fclose(f);
}
}
if (!found_something) {
// last ditch effort for older redhat releases
f = fopen("/etc/redhat-release", "r");
if (f) {
fgets(buf, 256, f);
found_something = true;
strip_whitespace(buf);
safe_strcpy(dist_pretty, buf);
fclose(f);
}
}
if (found_something) {
strcat(os_version, " (");
if (strlen(dist_pretty)) {
strcat(os_version, dist_pretty);
} else {
if (strlen(dist_name)) {
strcat(os_version, dist_name);
strcat(os_version, " ");
}
if (strlen(dist_version)) {
strcat(os_version, dist_version);
strcat(os_version, " ");
}
if (strlen(dist_codename)) {
strcat(os_version, dist_codename);
strcat(os_version, " ");
}
strip_whitespace(os_version);
}
strcat(os_version, ")");
if (strlen(dist_name)) {
strcat(os_name, " ");
strcat(os_name, dist_name);
}
}
#endif //LINUX_LIKE_SYSTEM
return 0;
}

View File

@ -124,6 +124,7 @@ int HOST_INFO::parse(XML_PARSER& xp, bool static_items_only) {
if (xp.parse_double("d_free", d_free)) continue;
if (xp.parse_str("os_name", os_name, sizeof(os_name))) continue;
if (xp.parse_str("os_version", os_version, sizeof(os_version))) continue;
if (xp.parse_str("product_name", product_name, sizeof(product_name))) continue;
if (xp.parse_str("virtualbox_version", virtualbox_version, sizeof(virtualbox_version))) continue;
if (xp.match_tag("coprocs")) {
this->coprocs.parse(xp);

View File

@ -62,7 +62,6 @@ public:
char os_name[256];
char os_version[256];
char product_name[256]; // manufacturer and/or model of system
// currently used for Android devices
char mac_address[256]; // MAC addr e.g. 00:00:00:00:00:00
// currently populated for Android

View File

@ -332,6 +332,60 @@ void strip_whitespace(string& str) {
str.erase(n, str.length()-n);
}
// remove whitespace and quotes from start and end of a string
//
void strip_quotes(char *str) {
char *s = str;
while (*s) {
if (*s == '"' || *s == '\'') {
s++;
continue;
}
if (!isascii(*s)) break;
if (!isspace(*s)) break;
s++;
}
if (s != str) strcpy_overlap(str, s);
size_t n = strlen(str);
while (n>0) {
n--;
if (str[n] == '"' || str[n] == '\'') {
str[n] = 0;
continue;
}
if (!isascii(str[n])) break;
if (!isspace(str[n])) break;
str[n] = 0;
}
}
void strip_quotes(string& str) {
while (1) {
if (str.length() == 0) break;
if (str[0] == '"' || str[0] == '\'') {
str.erase(0, 1);
continue;
}
if (!isascii(str[0])) break;
if (!isspace(str[0])) break;
str.erase(0, 1);
}
int n = (int) str.length();
while (n>0) {
if (str[n-1] == '"' || str[n-1] == '\'') {
n--;
continue;
}
if (!isascii(str[n-1])) break;
if (!isspace(str[n-1])) break;
n--;
}
str.erase(n, str.length()-n);
}
char* time_to_string(double t) {
static char buf[100];
if (!t) {

View File

@ -29,6 +29,8 @@ extern int parse_command_line(char*, char**);
extern void c2x(char *what);
extern void strip_whitespace(char *str);
extern void strip_whitespace(std::string&);
extern void strip_quotes(char *str);
extern void strip_quotes(std::string&);
extern char* time_to_string(double);
extern char* precision_time_to_string(double);
extern void secs_to_hmsf(double, char*);