diff options
Diffstat (limited to 'modules/computer/os.c')
-rw-r--r-- | modules/computer/os.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/modules/computer/os.c b/modules/computer/os.c new file mode 100644 index 00000000..7648eef3 --- /dev/null +++ b/modules/computer/os.c @@ -0,0 +1,582 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 or later. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <gdk/gdkx.h> +#include <string.h> +#include <sys/utsname.h> +#include "hardinfo.h" +#include "computer.h" +#include "distro_flavors.h" + +static gchar * +get_libc_version(void) +{ + static const struct { + const char *test_cmd; + const char *match_str; + const char *lib_name; + gboolean try_ver_str; + gboolean use_stderr; + } libs[] = { + { "ldd --version", "GLIBC", N_("GNU C Library"), TRUE, FALSE}, + { "ldd --version", "GNU libc", N_("GNU C Library"), TRUE, FALSE}, + { "ldconfig -V", "GLIBC", N_("GNU C Library"), TRUE, FALSE}, + { "ldconfig -V", "GNU libc", N_("GNU C Library"), TRUE, FALSE}, + { "ldconfig -v", "uClibc", N_("uClibc or uClibc-ng"), FALSE, FALSE}, + { "diet", "diet version", N_("diet libc"), TRUE, TRUE}, + { NULL } + }; + int i; + + for (i = 0; libs[i].test_cmd; i++) { + gboolean spawned; + gchar *out, *err, *p; + + spawned = hardinfo_spawn_command_line_sync(libs[i].test_cmd, + &out, &err, NULL, NULL); + if (!spawned) + continue; + + if (libs[i].use_stderr) { + p = strend(idle_free(err), '\n'); + g_free(out); + } else { + p = strend(idle_free(out), '\n'); + g_free(err); + } + + if (!p || !strstr(p, libs[i].match_str)) + continue; + + if (libs[i].try_ver_str) { + /* skip the first word, likely "ldconfig" or name of utility */ + const gchar *ver_str = strchr(p, ' '); + + if (ver_str) { + return g_strdup_printf("%s / %s", _(libs[i].lib_name), + ver_str + 1); + } + } + + return g_strdup(_(libs[i].lib_name)); + } + + return g_strdup(_("Unknown")); +} + +static gchar *detect_kde_version(void) +{ + const gchar *cmd; + const gchar *tmp = g_getenv("KDE_SESSION_VERSION"); + gchar *out; + gboolean spawned; + + if (tmp && tmp[0] == '4') { + cmd = "kwin --version"; + } else { + cmd = "kcontrol --version"; + } + + spawned = hardinfo_spawn_command_line_sync(cmd, &out, NULL, NULL, NULL); + if (!spawned) + return NULL; + + tmp = strstr(idle_free(out), "KDE: "); + return tmp ? g_strdup(tmp + strlen("KDE: ")) : NULL; +} + +static gchar * +detect_gnome_version(void) +{ + gchar *tmp; + gchar *out; + gboolean spawned; + + spawned = hardinfo_spawn_command_line_sync( + "gnome-shell --version", &out, NULL, NULL, NULL); + if (spawned) { + tmp = strstr(idle_free(out), _("GNOME Shell ")); + + if (tmp) { + tmp += strlen(_("GNOME Shell ")); + return g_strdup_printf("GNOME %s", strend(tmp, '\n')); + } + } + + spawned = hardinfo_spawn_command_line_sync( + "gnome-about --gnome-version", &out, NULL, NULL, NULL); + if (spawned) { + tmp = strstr(idle_free(out), _("Version: ")); + + if (tmp) { + tmp += strlen(_("Version: ")); + return g_strdup_printf("GNOME %s", strend(tmp, '\n')); + } + } + + return NULL; +} + + +static gchar * +detect_mate_version(void) +{ + gchar *tmp; + gchar *out; + gboolean spawned; + + spawned = hardinfo_spawn_command_line_sync( + "mate-about --version", &out, NULL, NULL, NULL); + if (spawned) { + tmp = strstr(idle_free(out), _("MATE Desktop Environment ")); + + if (tmp) { + tmp += strlen(_("MATE Desktop Environment ")); + return g_strdup_printf("MATE %s", strend(tmp, '\n')); + } + } + + return NULL; +} + +static gchar * +detect_window_manager(void) +{ + const gchar *curdesktop; + const gchar* windowman; + GdkScreen *screen = gdk_screen_get_default(); + +#if GTK_CHECK_VERSION(3,0,0) + if (GDK_IS_X11_SCREEN(screen)) { +#else + if (screen && GDK_IS_SCREEN(screen)) { +#endif + windowman = gdk_x11_screen_get_window_manager_name(screen); + } else return g_strdup("Not X11"); + + if (g_str_equal(windowman, "Xfwm4")) + return g_strdup("XFCE 4"); + + curdesktop = g_getenv("XDG_CURRENT_DESKTOP"); + if (curdesktop) { + const gchar *desksession = g_getenv("DESKTOP_SESSION"); + + if (desksession && !g_str_equal(curdesktop, desksession)) + return g_strdup(desksession); + } + + return g_strdup_printf(_("Unknown (Window Manager: %s)"), windowman); +} + +static gchar * +desktop_with_session_type(const gchar *desktop_env) +{ + const char *tmp; + + tmp = g_getenv("XDG_SESSION_TYPE"); + if (tmp) { + if (!g_str_equal(tmp, "unspecified")) + return g_strdup_printf(_(/*/{desktop environment} on {session type}*/ "%s on %s"), desktop_env, tmp); + } + + return g_strdup(desktop_env); +} + +static gchar * +detect_xdg_environment(const gchar *env_var) +{ + const gchar *tmp; + + tmp = g_getenv(env_var); + if (!tmp) + return NULL; + + if (g_str_equal(tmp, "GNOME") || g_str_equal(tmp, "gnome")) { + gchar *maybe_gnome = detect_gnome_version(); + + if (maybe_gnome) + return maybe_gnome; + } + if (g_str_equal(tmp, "KDE") || g_str_equal(tmp, "kde")) { + gchar *maybe_kde = detect_kde_version(); + + if (maybe_kde) + return maybe_kde; + } + if (g_str_equal(tmp, "MATE") || g_str_equal(tmp, "mate")) { + gchar *maybe_mate = detect_mate_version(); + + if (maybe_mate) + return maybe_mate; + } + + return g_strdup(tmp); +} + +static gchar * +detect_desktop_environment(void) +{ + const gchar *tmp; + gchar *windowman; + + windowman = detect_xdg_environment("XDG_CURRENT_DESKTOP"); + if (windowman) + return windowman; + windowman = detect_xdg_environment("XDG_SESSION_DESKTOP"); + if (windowman) + return windowman; + + tmp = g_getenv("KDE_FULL_SESSION"); + if (tmp) { + gchar *maybe_kde = detect_kde_version(); + + if (maybe_kde) + return maybe_kde; + } + tmp = g_getenv("GNOME_DESKTOP_SESSION_ID"); + if (tmp) { + gchar *maybe_gnome = detect_gnome_version(); + + if (maybe_gnome) + return maybe_gnome; + } + + windowman = detect_window_manager(); + if (windowman) + return windowman; + + if (!g_getenv("DISPLAY")) + return g_strdup(_("Terminal")); + + return g_strdup(_("Unknown")); +} + +gchar * +computer_get_dmesg_status(void) +{ + gchar *out = NULL, *err = NULL; + int ex = 1, result = 0; + hardinfo_spawn_command_line_sync("dmesg", &out, &err, &ex, NULL); + g_free(out); + g_free(err); + result += (getuid() == 0) ? 2 : 0; + result += ex ? 1 : 0; + switch(result) { + case 0: /* readable, user */ + return g_strdup(_("User access allowed")); + case 1: /* unreadable, user */ + return g_strdup(_("User access forbidden")); + case 2: /* readable, root */ + return g_strdup(_("Access allowed (running as superuser)")); + case 3: /* unreadable, root */ + return g_strdup(_("Access forbidden? (running as superuser)")); + } + return g_strdup(_("(Unknown)")); +} + +gchar * +computer_get_aslr(void) +{ + switch (h_sysfs_read_int("/proc/sys/kernel", "randomize_va_space")) { + case 0: + return g_strdup(_("Disabled")); + case 1: + return g_strdup(_("Partially enabled (mmap base+stack+VDSO base)")); + case 2: + return g_strdup(_("Fully enabled (mmap base+stack+VDSO base+heap)")); + default: + return g_strdup(_("Unknown")); + } +} + +gchar * +computer_get_entropy_avail(void) +{ + gchar tab_entropy_fstr[][32] = { + N_(/*/bits of entropy for rng (0)*/ "(None or not available)"), + N_(/*/bits of entropy for rng (low/poor value)*/ "%d bits (low)"), + N_(/*/bits of entropy for rng (medium value)*/ "%d bits (medium)"), + N_(/*/bits of entropy for rng (high/good value)*/ "%d bits (healthy)") + }; + gint bits = h_sysfs_read_int("/proc/sys/kernel/random", "entropy_avail"); + if (bits > 3000) return g_strdup_printf(_(tab_entropy_fstr[3]), bits); + if (bits > 200) return g_strdup_printf(_(tab_entropy_fstr[2]), bits); + if (bits > 1) return g_strdup_printf(_(tab_entropy_fstr[1]), bits); + return g_strdup_printf(_(tab_entropy_fstr[0]), bits); +} + +gchar * +computer_get_language(void) +{ + gchar *tab_lang_env[] = + { "LANGUAGE", "LANG", "LC_ALL", "LC_MESSAGES", NULL }; + gchar *lc = NULL, *env = NULL, *ret = NULL; + gint i = 0; + + lc = setlocale(LC_ALL, NULL); + + while (tab_lang_env[i] != NULL) { + env = g_strdup( g_getenv(tab_lang_env[i]) ); + if (env != NULL) break; + i++; + } + + if (env != NULL) + if (lc != NULL) + ret = g_strdup_printf("%s (%s)", lc, env); + else + ret = g_strdup_printf("%s", env); + else + if (lc != NULL) + ret = g_strdup_printf("%s", lc); + + if (ret == NULL) + ret = g_strdup( _("(Unknown)") ); + + return ret; +} + +static Distro +parse_os_release(void) +{ + gchar *pretty_name = NULL; + gchar *id = NULL; + gchar *codename = NULL; + gchar **split, *contents, **line; + + if (!g_file_get_contents("/usr/lib/os-release", &contents, NULL, NULL)) + return (Distro) {}; + + split = g_strsplit(idle_free(contents), "\n", 0); + if (!split) + return (Distro) {}; + + for (line = split; *line; line++) { + if (!strncmp(*line, "ID=", sizeof("ID=") - 1)) { + id = g_strdup(*line + strlen("ID=")); + } else if (!strncmp(*line, "CODENAME=", sizeof("CODENAME=") - 1)) { + codename = g_strdup(*line + strlen("CODENAME=")); + } else if (!strncmp(*line, "PRETTY_NAME=", sizeof("PRETTY_NAME=") - 1)) { + pretty_name = g_strdup(*line + + strlen("PRETTY_NAME=\"")); + strend(pretty_name, '"'); + } + } + + g_strfreev(split); + + if (pretty_name) + return (Distro) { .distro = pretty_name, .codename = codename, .id = id }; + + g_free(id); + return (Distro) {}; +} + +static Distro +parse_lsb_release(void) +{ + gchar *pretty_name = NULL; + gchar *id = NULL; + gchar *codename = NULL; + gchar **split, *contents, **line; + + if (!hardinfo_spawn_command_line_sync("/usr/bin/lsb_release -di", &contents, NULL, NULL, NULL)) + return (Distro) {}; + + split = g_strsplit(idle_free(contents), "\n", 0); + if (!split) + return (Distro) {}; + + for (line = split; *line; line++) { + if (!strncmp(*line, "Distributor ID:\t", sizeof("Distributor ID:\t") - 1)) { + id = g_utf8_strdown(*line + strlen("Distributor ID:\t"), -1); + } else if (!strncmp(*line, "Codename:\t", sizeof("Codename:\t") - 1)) { + codename = g_utf8_strdown(*line + strlen("Codename:\t"), -1); + } else if (!strncmp(*line, "Description:\t", sizeof("Description:\t") - 1)) { + pretty_name = g_strdup(*line + strlen("Description:\t")); + } + } + + g_strfreev(split); + + if (pretty_name) + return (Distro) { .distro = pretty_name, .codename = codename, .id = id }; + + g_free(id); + return (Distro) {}; +} + +static Distro +detect_distro(void) +{ + static const struct { + const gchar *file; + const gchar *codename; + const gchar *override; + } distro_db[] = { +#define DB_PREFIX "/etc/" + { DB_PREFIX "arch-release", "arch", "Arch Linux" }, + { DB_PREFIX "fatdog-version", "fatdog" }, + { DB_PREFIX "debian_version", "debian" }, + { DB_PREFIX "slackware-version", "slk" }, + { DB_PREFIX "mandrake-release", "mdk" }, + { DB_PREFIX "mandriva-release", "mdv" }, + { DB_PREFIX "fedora-release", "fedora" }, + { DB_PREFIX "coas", "coas" }, + { DB_PREFIX "environment.corel", "corel"}, + { DB_PREFIX "gentoo-release", "gnt" }, + { DB_PREFIX "conectiva-release", "cnc" }, + { DB_PREFIX "versão-conectiva", "cnc" }, + { DB_PREFIX "turbolinux-release", "tl" }, + { DB_PREFIX "yellowdog-release", "yd" }, + { DB_PREFIX "sabayon-release", "sbn" }, + { DB_PREFIX "enlisy-release", "enlsy" }, + { DB_PREFIX "SuSE-release", "suse" }, + { DB_PREFIX "sun-release", "sun" }, + { DB_PREFIX "zenwalk-version", "zen" }, + { DB_PREFIX "DISTRO_SPECS", "ppy", "Puppy Linux" }, + { DB_PREFIX "puppyversion", "ppy", "Puppy Linux" }, + { DB_PREFIX "distro-release", "fl" }, + { DB_PREFIX "vine-release", "vine" }, + { DB_PREFIX "PartedMagic-version", "pmag" }, + /* + * RedHat must be the *last* one to be checked, since + * some distros (like Mandrake) includes a redhat-relase + * file too. + */ + { DB_PREFIX "redhat-release", "rh" }, +#undef DB_PREFIX + { NULL, NULL } + }; + Distro distro; + gchar *contents; + int i; + + distro = parse_os_release(); + if (distro.distro) + return distro; + + distro = parse_lsb_release(); + if (distro.distro) + return distro; + + for (i = 0; distro_db[i].file; i++) { + if (!g_file_get_contents(distro_db[i].file, &contents, NULL, NULL)) + continue; + + if (distro_db[i].override) { + g_free(contents); + return (Distro) { .distro = g_strdup(distro_db[i].override), + .codename = g_strdup(distro_db[i].codename) }; + } + + if (g_str_equal(distro_db[i].codename, "debian")) { + /* HACK: Some Debian systems doesn't include the distribuition + * name in /etc/debian_release, so add them here. */ + if (isdigit(contents[0]) || contents[0] != 'D') + return (Distro) { + .distro = g_strdup_printf("Debian GNU/Linux %s", (char*)idle_free(contents)), + .codename = g_strdup(distro_db[i].codename) + }; + } + + if (g_str_equal(distro_db[i].codename, "fatdog")) { + return (Distro) { + .distro = g_strdup_printf("Fatdog64 [%.10s]", (char*)idle_free(contents)), + .codename = g_strdup(distro_db[i].codename) + }; + } + + return (Distro) { .distro = contents, .codename = g_strdup(distro_db[i].codename) }; + } + + return (Distro) { .distro = g_strdup(_("Unknown")) }; +} + +OperatingSystem * +computer_get_os(void) +{ + struct utsname utsbuf; + OperatingSystem *os; + int i; + + os = g_new0(OperatingSystem, 1); + + Distro distro = detect_distro(); + os->distro = g_strstrip(distro.distro); + os->distroid = distro.id; + os->distrocode = distro.codename; + + /* Kernel and hostname info */ + uname(&utsbuf); + os->kernel_version = g_strdup(utsbuf.version); + os->kernel = g_strdup_printf("%s %s (%s)", utsbuf.sysname, + utsbuf.release, utsbuf.machine); + os->kcmdline = h_sysfs_read_string("/proc", "cmdline"); + os->hostname = g_strdup(utsbuf.nodename); + os->language = computer_get_language(); + os->homedir = g_strdup(g_get_home_dir()); + os->username = g_strdup_printf("%s (%s)", + g_get_user_name(), g_get_real_name()); + os->libc = get_libc_version(); + scan_languages(os); + + os->desktop = detect_desktop_environment(); + if (os->desktop) + os->desktop = desktop_with_session_type(idle_free(os->desktop)); + + os->entropy_avail = computer_get_entropy_avail(); + + if (g_strcmp0(os->distrocode, "ubuntu") == 0) { + GSList *flavs = ubuntu_flavors_scan(); + if (flavs) { + /* just use the first one */ + os->distro_flavor = (DistroFlavor*)flavs->data; + } + g_slist_free(flavs); + } + + return os; +} + +const gchar * +computer_get_selinux(void) +{ + int r; + gboolean spawned = hardinfo_spawn_command_line_sync("selinuxenabled", + NULL, NULL, &r, NULL); + + if (!spawned) + return _("Not installed"); + + if (r == 0) + return _("Enabled"); + + return _("Disabled"); +} + +gchar * +computer_get_lsm(void) +{ + gchar *contents; + + if (!g_file_get_contents("/sys/kernel/security/lsm", &contents, NULL, NULL)) + return g_strdup(_("Unknown")); + + return contents; +} |