diff options
Diffstat (limited to 'src/libimcv/os_info/os_info.c')
-rw-r--r-- | src/libimcv/os_info/os_info.c | 553 |
1 files changed, 4 insertions, 549 deletions
diff --git a/src/libimcv/os_info/os_info.c b/src/libimcv/os_info/os_info.c index 06427575c..258b8b442 100644 --- a/src/libimcv/os_info/os_info.c +++ b/src/libimcv/os_info/os_info.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Andreas Steffen + * Copyright (C) 2012-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,16 +15,7 @@ #include "os_info.h" -#include <sys/utsname.h> -#include <stdio.h> -#include <stdarg.h> - -#include <collections/linked_list.h> -#include <utils/debug.h> - -typedef struct private_os_info_t private_os_info_t; - -ENUM(os_type_names, OS_TYPE_UNKNOWN, OS_TYPE_ANDROID, +ENUM(os_type_names, OS_TYPE_UNKNOWN, OS_TYPE_WINDOWS, "Unknown", "Debian", "Ubuntu", @@ -33,7 +24,8 @@ ENUM(os_type_names, OS_TYPE_UNKNOWN, OS_TYPE_ANDROID, "CentOS", "SUSE", "Gentoo", - "Android" + "Android", + "Windows", ); ENUM(os_fwd_status_names, OS_FWD_DISABLED, OS_FWD_UNKNOWN, @@ -49,487 +41,6 @@ ENUM(os_package_state_names, OS_PACKAGE_STATE_UPDATE, OS_PACKAGE_STATE_BLACKLIST ); /** - * Private data of an os_info_t object. - * - */ -struct private_os_info_t { - - /** - * Public os_info_t interface. - */ - os_info_t public; - - /** - * OS type - */ - os_type_t type; - - /** - * OS name - */ - chunk_t name; - - /** - * OS version - */ - chunk_t version; - -}; - -METHOD(os_info_t, get_type, os_type_t, - private_os_info_t *this) -{ - return this->type; -} - -METHOD(os_info_t, get_name, chunk_t, - private_os_info_t *this) -{ - return this->name; -} - -METHOD(os_info_t, get_numeric_version, void, - private_os_info_t *this, u_int32_t *major, u_int32_t *minor) -{ - u_char *pos; - - if (major) - { - *major = atol(this->version.ptr); - } - pos = memchr(this->version.ptr, '.', this->version.len); - if (minor) - { - *minor = pos ? atol(pos + 1) : 0; - } -} - -METHOD(os_info_t, get_version, chunk_t, - private_os_info_t *this) -{ - return this->version; -} - -METHOD(os_info_t, get_fwd_status, os_fwd_status_t, - private_os_info_t *this) -{ - const char ip_forward[] = "/proc/sys/net/ipv4/ip_forward"; - char buf[2]; - FILE *file; - - os_fwd_status_t fwd_status = OS_FWD_UNKNOWN; - - file = fopen(ip_forward, "r"); - if (file) - { - if (fread(buf, 1, 1, file) == 1) - { - switch (buf[0]) - { - case '0': - fwd_status = OS_FWD_DISABLED; - break; - case '1': - fwd_status = OS_FWD_ENABLED; - break; - default: - DBG1(DBG_IMC, "\"%s\" returns invalid value ", ip_forward); - break; - } - } - else - { - DBG1(DBG_IMC, "could not read from \"%s\"", ip_forward); - } - fclose(file); - } - else - { - DBG1(DBG_IMC, "failed to open \"%s\"", ip_forward); - } - - return fwd_status; -} - -METHOD(os_info_t, get_uptime, time_t, - private_os_info_t *this) -{ - const char proc_uptime[] = "/proc/uptime"; - FILE *file; - u_int uptime; - - file = fopen(proc_uptime, "r"); - if (!file) - { - DBG1(DBG_IMC, "failed to open \"%s\"", proc_uptime); - return 0; - } - if (fscanf(file, "%u", &uptime) != 1) - { - DBG1(DBG_IMC, "failed to read file \"%s\"", proc_uptime); - uptime = 0; - } - fclose(file); - - return uptime; -} - -METHOD(os_info_t, get_setting, chunk_t, - private_os_info_t *this, char *name) -{ - FILE *file; - u_char buf[2048]; - size_t i = 0; - chunk_t value; - - if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") && - !strpfx(name, "/sys/") && !strpfx(name, "/var/")) - { - /** - * In order to guarantee privacy, only settings from the - * /etc/, /proc/ and /sys/ directories can be retrieved - */ - DBG1(DBG_IMC, "not allowed to access '%s'", name); - - return chunk_empty; - } - - file = fopen(name, "r"); - if (!file) - { - DBG1(DBG_IMC, "failed to open '%s'", name); - - return chunk_empty; - } - while (i < sizeof(buf) && fread(buf + i, 1, 1, file) == 1) - { - i++; - } - fclose(file); - - value = chunk_create(buf, i); - - return chunk_clone(value); -} - -typedef struct { - /** - * implements enumerator_t - */ - enumerator_t public; - - /** - * package info pipe stream - */ - FILE* file; - - /** - * line buffer - */ - u_char line[512]; - -} package_enumerator_t; - -/** - * Implementation of package_enumerator.destroy. - */ -static void package_enumerator_destroy(package_enumerator_t *this) -{ - pclose(this->file); - free(this); -} - -/** - * Implementation of package_enumerator.enumerate - */ -static bool package_enumerator_enumerate(package_enumerator_t *this, ...) -{ - chunk_t *name, *version; - u_char *pos; - va_list args; - - while (TRUE) - { - if (!fgets(this->line, sizeof(this->line), this->file)) - { - return FALSE; - } - - pos = strchr(this->line, '\t'); - if (!pos) - { - return FALSE; - } - *pos++ = '\0'; - - if (!streq(this->line, "install ok installed")) - { - continue; - } - va_start(args, this); - - name = va_arg(args, chunk_t*); - name->ptr = pos; - pos = strchr(pos, '\t'); - if (!pos) - { - va_end(args); - return FALSE; - } - name->len = pos++ - name->ptr; - - version = va_arg(args, chunk_t*); - version->ptr = pos; - version->len = strlen(pos) - 1; - - va_end(args); - return TRUE; - } -} - -METHOD(os_info_t, create_package_enumerator, enumerator_t*, - private_os_info_t *this) -{ - FILE *file; - const char command[] = "dpkg-query --show --showformat=" - "'${Status}\t${Package}\t${Version}\n'"; - package_enumerator_t *enumerator; - - /* Only Debian and Ubuntu package enumeration is currently supported */ - if (this->type != OS_TYPE_DEBIAN && this->type != OS_TYPE_UBUNTU) - { - return NULL; - } - - /* Open a pipe stream for reading the output of the dpkg-query commmand */ - file = popen(command, "r"); - if (!file) - { - DBG1(DBG_IMC, "failed to run dpkg command"); - return NULL; - } - - /* Create a package enumerator instance */ - enumerator = malloc_thing(package_enumerator_t); - enumerator->public.enumerate = (void*)package_enumerator_enumerate; - enumerator->public.destroy = (void*)package_enumerator_destroy; - enumerator->file = file; - - return (enumerator_t*)enumerator; -} - - -METHOD(os_info_t, destroy, void, - private_os_info_t *this) -{ - free(this->name.ptr); - free(this->version.ptr); - free(this); -} - -#define RELEASE_LSB 0 -#define RELEASE_DEBIAN 1 - -/** - * Determine Linux distribution version and hardware platform - */ -static bool extract_platform_info(os_type_t *type, chunk_t *name, - chunk_t *version) -{ - FILE *file; - u_char buf[BUF_LEN], *pos = buf; - int len = BUF_LEN - 1; - os_type_t os_type = OS_TYPE_UNKNOWN; - chunk_t os_name = chunk_empty; - chunk_t os_version = chunk_empty; - char *os_str; - struct utsname uninfo; - int i; - - /* Linux/Unix distribution release info (from http://linuxmafia.com) */ - const char* releases[] = { - "/etc/lsb-release", "/etc/debian_version", - "/etc/SuSE-release", "/etc/novell-release", - "/etc/sles-release", "/etc/redhat-release", - "/etc/fedora-release", "/etc/gentoo-release", - "/etc/slackware-version", "/etc/annvix-release", - "/etc/arch-release", "/etc/arklinux-release", - "/etc/aurox-release", "/etc/blackcat-release", - "/etc/cobalt-release", "/etc/conectiva-release", - "/etc/debian_release", "/etc/immunix-release", - "/etc/lfs-release", "/etc/linuxppc-release", - "/etc/mandrake-release", "/etc/mandriva-release", - "/etc/mandrakelinux-release", "/etc/mklinux-release", - "/etc/pld-release", "/etc/redhat_version", - "/etc/slackware-release", "/etc/e-smith-release", - "/etc/release", "/etc/sun-release", - "/etc/tinysofa-release", "/etc/turbolinux-release", - "/etc/ultrapenguin-release", "/etc/UnitedLinux-release", - "/etc/va-release", "/etc/yellowdog-release" - }; - - const char lsb_distrib_id[] = "DISTRIB_ID="; - const char lsb_distrib_release[] = "DISTRIB_RELEASE="; - - for (i = 0; i < countof(releases); i++) - { - file = fopen(releases[i], "r"); - if (!file) - { - continue; - } - - /* read release file into buffer */ - fseek(file, 0, SEEK_END); - len = min(ftell(file), len); - rewind(file); - buf[len] = '\0'; - if (fread(buf, 1, len, file) != len) - { - DBG1(DBG_IMC, "failed to read file \"%s\"", releases[i]); - fclose(file); - return FALSE; - } - fclose(file); - - DBG1(DBG_IMC, "processing \"%s\" file", releases[i]); - - switch (i) - { - case RELEASE_LSB: - { - /* Determine Distribution ID */ - pos = strstr(buf, lsb_distrib_id); - if (!pos) - { - DBG1(DBG_IMC, "failed to find begin of DISTRIB_ID field"); - return FALSE; - } - pos += strlen(lsb_distrib_id); - - os_name.ptr = pos; - - pos = strchr(pos, '\n'); - if (!pos) - { - DBG1(DBG_IMC, "failed to find end of DISTRIB_ID field"); - return FALSE; - } - os_name.len = pos - os_name.ptr; - - /* Determine Distribution Release */ - pos = strstr(buf, lsb_distrib_release); - if (!pos) - { - DBG1(DBG_IMC, "failed to find begin of DISTRIB_RELEASE field"); - return FALSE; - } - pos += strlen(lsb_distrib_release); - - os_version.ptr = pos; - - pos = strchr(pos, '\n'); - if (!pos) - { - DBG1(DBG_IMC, "failed to find end of DISTRIB_RELEASE field"); - return FALSE; - } - os_version.len = pos - os_version.ptr; - - break; - } - case RELEASE_DEBIAN: - { - os_type = OS_TYPE_DEBIAN; - - os_version.ptr = buf; - pos = strchr(buf, '\n'); - if (!pos) - { - DBG1(DBG_PTS, "failed to find end of release string"); - return FALSE; - } - - os_version.len = pos - os_version.ptr; - - break; - } - default: - { - const char str_release[] = " release "; - - os_name.ptr = buf; - - pos = strstr(buf, str_release); - if (!pos) - { - DBG1(DBG_IMC, "failed to find release keyword"); - return FALSE; - } - - os_name.len = pos - os_name.ptr; - - pos += strlen(str_release); - os_version.ptr = pos; - - pos = strchr(pos, '\n'); - if (!pos) - { - DBG1(DBG_IMC, "failed to find end of release string"); - return FALSE; - } - - os_version.len = pos - os_version.ptr; - - break; - } - } - break; - } - - if (!os_version.ptr) - { - DBG1(DBG_IMC, "no distribution release file found"); - return FALSE; - } - - if (uname(&uninfo) < 0) - { - DBG1(DBG_IMC, "could not retrieve machine architecture"); - return FALSE; - } - - /* Try to find a matching OS type based on the OS name */ - if (os_type == OS_TYPE_UNKNOWN) - { - os_type = os_type_from_name(os_name); - } - - /* If known use the official OS name */ - if (os_type != OS_TYPE_UNKNOWN) - { - os_str = enum_to_name(os_type_names, os_type); - os_name = chunk_create(os_str, strlen(os_str)); - } - - /* copy OS type */ - *type = os_type; - - /* copy OS name */ - *name = chunk_clone(os_name); - - /* copy OS version and machine architecture */ - *version = chunk_alloc(os_version.len + 1 + strlen(uninfo.machine)); - pos = version->ptr; - memcpy(pos, os_version.ptr, os_version.len); - pos += os_version.len; - *pos++ = ' '; - memcpy(pos, uninfo.machine, strlen(uninfo.machine)); - - return TRUE; -} - -/** * See header */ os_type_t os_type_from_name(chunk_t name) @@ -548,59 +59,3 @@ os_type_t os_type_from_name(chunk_t name) } return OS_TYPE_UNKNOWN; } - -/** - * See header - */ -os_info_t *os_info_create(void) -{ - private_os_info_t *this; - chunk_t name, version; - os_type_t type; - - /* As an option OS name and OS version can be configured manually */ - name.ptr = lib->settings->get_str(lib->settings, - "%s.imcv.os_info.name", NULL, lib->ns); - version.ptr = lib->settings->get_str(lib->settings, - "%s.imcv.os_info.version", NULL, lib->ns); - if (name.ptr && version.ptr) - { - name.len = strlen(name.ptr); - name = chunk_clone(name); - - version.len = strlen(version.ptr); - version = chunk_clone(version); - - type = os_type_from_name(name); - } - else - { - if (!extract_platform_info(&type, &name, &version)) - { - return NULL; - } - } - DBG1(DBG_IMC, "operating system name is '%.*s'", - name.len, name.ptr); - DBG1(DBG_IMC, "operating system version is '%.*s'", - version.len, version.ptr); - - INIT(this, - .public = { - .get_type = _get_type, - .get_name = _get_name, - .get_numeric_version = _get_numeric_version, - .get_version = _get_version, - .get_fwd_status = _get_fwd_status, - .get_uptime = _get_uptime, - .get_setting = _get_setting, - .create_package_enumerator = _create_package_enumerator, - .destroy = _destroy, - }, - .type = type, - .name = name, - .version = version, - ); - - return &this->public; -} |