Logo Search packages:      
Sourcecode: hardinfo version File versions  Download package

computer.c

/*
 * Distribuition detection routines
 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
 *
 * May be distributed under the terms of GNU General Public License version 2.
 */

#include "hardinfo.h"
#include "computer.h"

#include <gtk/gtk.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

static struct {
    gchar *file, *codename;
} distro_db[] = {
    {    DB_PREFIX "debian_version",            "deb" },
    {    DB_PREFIX "slackware-version",         "slk" },
    {    DB_PREFIX "mandrake-release",          "mdk" }, 
    {    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 "SuSE-release",        "suse"      },
      /*
       * 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"  },
    {    NULL, NULL                               }
};

#define get_int_val(var)  { \
            walk_until_inclusive(':'); buf++; \
            var = atoi(buf); \
            continue; \
      }

#define get_str_val(var)  { \
            walk_until_inclusive(':'); buf++; \
            var = g_strdup(buf); \
            continue; \
      }

#ifdef ARCH_i386
static struct {
    char *small, *large;
} small2large[] = {
      {    "fpu", "Floating Point Unit"                     },
      {    "vme", "Virtual Mode Extension"                  },
      {    "de",  "Debugging Extensions"                    },
      {    "pse", "Page Size Extensions"                    },
      {    "tsc", "Time Stamp Counter"                      },
      {    "msr", "Model Specific Registers"                },
      {    "pae", "Physical Address Extensions"             },
      {    "mce", "Machine Check Architeture"               },
      {    "cx8", "CMPXCHG8 instruction"                    },
      {    "apic",      "Advanced Programmable Interrupt Controller"    },
      {    "sep", "Fast System Call"                        },
      {    "mtrr",      "Memory Type Range Registers"             },
      {    "pge", "Page Global Enable"                      },
      {    "cmov",      "Conditional Move instruction"                  },
      {    "pat", "Page Attribute Table"                    },
      {    "pse36",     "36bit Page Size Extensions"              },
      {    "psn", "96 bit Processor Serial Number"          },
      {    "mmx", "MMX technology"                    },
      {    "fxsr",      "fxsr"                                    },
      {    "kni", "Streaming SIMD instructions"             },
      {    "xmm", "Streaming SIMD instructions"             },
      {    "ht",      "HyperThreading"                                },
      {    NULL,  NULL                                }
};

static GtkWidget *get_features_widget(CPUDevice * device)
{
    GtkWidget *widget, *scroll;
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    gchar **flags;
    gint i, j;

    if (!device->flags)
      return NULL;

    buffer = gtk_text_buffer_new(FALSE);
    gtk_text_buffer_set_text(buffer, "", -1);
    gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);

    flags = g_strsplit(device->flags, " ", G_N_ELEMENTS(small2large));
    for (i = 0; *(flags + i); i++) {
      for (j = 0; j < G_N_ELEMENTS(small2large); j++) {
          if (small2large[j].small &&
            !strncmp(small2large[j].small, *(flags + i),
                   strlen(small2large[j].small))) {
//          gtk_text_buffer_insert(buffer, &iter, small2large[j].small,
//                             -1);
            gtk_text_buffer_insert(buffer, &iter, "● ", -1);
            gtk_text_buffer_insert(buffer, &iter, small2large[j].large,
                               -1);
            gtk_text_buffer_insert(buffer, &iter, "\n", -1);
            break;
          }
      }
    }
    g_strfreev(flags);

    scroll = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
                           GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
    gtk_container_set_border_width(GTK_CONTAINER(scroll), 4);
    gtk_widget_show(scroll);

    widget = gtk_text_view_new();
    gtk_text_view_set_buffer(GTK_TEXT_VIEW(widget), buffer);
    gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(widget), FALSE);
    gtk_text_view_set_indent(GTK_TEXT_VIEW(widget), 5);
    gtk_widget_show(widget);

    gtk_container_add(GTK_CONTAINER(scroll), widget);

    return scroll;
}
#endif

void hi_show_cpu_info(MainWindow * mainwindow, CPUDevice * device)
{
    gchar *buf;

    if (!device)
      return;

    gtk_window_set_title(GTK_WINDOW(mainwindow->det_window->window),
                   device->processor);
    detail_window_set_icon(mainwindow->det_window, IMG_PREFIX "cpu.png");
    detail_window_set_dev_name(mainwindow->det_window, device->processor);
    detail_window_set_dev_type(mainwindow->det_window, device->machine);

    detail_window_append_info_int(mainwindow->det_window, _("Number"),
                          device->procno, FALSE);
    buf = g_strdup_printf("%dMHz", device->frequency);
    detail_window_append_info(mainwindow->det_window, _("Frequency"), buf);
    g_free(buf);

    detail_window_append_separator(mainwindow->det_window);
#ifdef ARCH_i386
    detail_window_append_info_int(mainwindow->det_window, _("Family"),
                          device->family, FALSE);
    detail_window_append_info_int(mainwindow->det_window, _("Model"),
                          device->model, FALSE);
    detail_window_append_info_int(mainwindow->det_window, _("Stepping"),
                          device->stepping, FALSE);
    detail_window_append_separator(mainwindow->det_window);
#endif

    if (device->cachel2) {
      buf = g_strdup_printf("%dkB", device->cachel2);
      detail_window_append_info(mainwindow->det_window, _("Cache L2"),
                          buf);
      g_free(buf);
    }

    buf = g_strdup_printf("%d bogomips", device->bogomips);
    detail_window_append_info(mainwindow->det_window, _("Bogomips"), buf);
    g_free(buf);

#ifdef ARCH_i386
    {
      GtkWidget *features, *label;

      label = gtk_label_new(_("Features"));
      gtk_widget_show(label);

      features = get_features_widget(device);
      gtk_notebook_append_page(GTK_NOTEBOOK
                         (mainwindow->det_window->notebook),
                         features, label);
    }
#endif

}

MemoryInfo *memory_get_info(void)
{
    MemoryInfo *mi;
    FILE *procmem;
    gchar buffer[128];
    gint memfree = 0, memused;

    mi = g_new0(MemoryInfo, 1);

    procmem = fopen("/proc/meminfo", "r");
    while (fgets(buffer, 128, procmem)) {
      gchar *buf = buffer;

      buf = g_strstrip(buf);

      if (!strncmp(buf, "MemTotal", 8))
          get_int_val(mi->total)
      else if (!strncmp(buf, "MemFree", 7))
          get_int_val(memfree)
      else if (!strncmp(buf, "Cached", 6))
          get_int_val(mi->cached)
    }
    fclose(procmem);

    mi->used = mi->total - memfree;

    mi->total  /= 1000;
    mi->cached /= 1000;
    mi->used   /= 1000;
    memfree    /= 1000;

    memused = mi->total - mi->used + mi->cached;

    mi->ratio = 1 - (gdouble) memused / mi->total;

    return mi;
}

#if defined(ARCH_i386) || defined(ARCH_x86_64) || defined(ARCH_PARISC)
#define PARSE_PROC_CPU()                              \
            if(!strncmp(buf, "bogomips", 8))          \
                  get_int_val(ci->bogomips)           \
            else if(!strncmp(buf, "cpu family", 10))  \
                  get_int_val(ci->family)             \
            else if(!strncmp(buf, "model name", 10))  \
                  get_str_val(ci->processor)          \
            else if(!strncmp(buf, "flags", 5))        \
                  get_str_val(ci->flags)              \
            else if(!strncmp(buf, "vendor_id", 8))          \
                  get_str_val(ci->machine)            \
            else if(!strncmp(buf, "stepping", 8))           \
                  get_int_val(ci->stepping)           \
            else if(!strncmp(buf, "cpu MHz", 7))            \
                  get_int_val(ci->frequency)          \
            else if(!strncmp(buf, "cache size", 10))  \
                  get_int_val(ci->cachel2)            \
            else if(!strncmp(buf, "model", 5))        \
                  get_int_val(ci->model)
#endif
#ifdef ARCH_PPC
#define PARSE_PROC_CPU()                              \
            if(!strncmp(buf, "bogomips", 8))          \
                  get_int_val(ci->bogomips)           \
            else if(!strncmp(buf, "cpu", 3))          \
                  get_str_val(ci->processor)          \
            else if(!strncmp(buf, "machine", 7))            \
                  get_str_val(ci->machine)            \
            else if(!strncmp(buf, "clock", 5))        \
                  get_int_val(ci->frequency)          \
            else if(!strncmp(buf, "L2 cache", 8))           \
                  get_int_val(ci->cachel2)
#endif
#ifdef ARCH_m68k
#define     PARSE_PROC_CPU()                          \
            if (!strncmp(buf, "CPU", 3))              \
                  get_str_val(ci->processor)          \
            else if (!strncmp(buf, "BogoMips", 8))          \
                  get_int_val(ci->bogomips)           \
            else if (!strncmp(buf, "Clocking", 8))          \
                  get_int_val(ci->frequency)
#endif
#ifdef ARCH_MIPS
#define     PARSE_PROC_CPU()                          \
                if (!strncmp(buf, "cpu model", 9))          \
                        get_str_val(ci->processor)          \
                else if (!strncmp(buf, "BogoMIPS", 8))            \
                        get_int_val(ci->bogomips)           \
                else if (!strncmp(buf, "system type", 11))  \
                        get_str_val(ci->machine)            
#endif

#ifndef PARSE_PROC_CPU
#error PARSE_PROC_CPU not defined! Maybe your arch is not supported yet;
#error please send me your /proc/cpuinfo and/or 'uname -a' output to
#error leandro@linuxmag.com.br; thanks.
#endif

static void computer_processor_info(ComputerInfo * ci)
{
    FILE *proccpu;
    gchar buffer[128];

    proccpu = fopen("/proc/cpuinfo", "r");
    while (fgets(buffer, 128, proccpu)) {
      gchar *buf = buffer;

      buf = g_strstrip(buf);

      PARSE_PROC_CPU();
    }
    fclose(proccpu);

#ifdef ARCH_PPC
    {
      gchar *proctemp;

      proctemp = g_strdup_printf("PowerPC %s", ci->processor);
      g_free(ci->processor);
      ci->processor = proctemp;
    }
#endif
#ifdef ARCH_m68k
    {
      gchar *proctemp;

      proctemp = g_strdup_printf("Motorola %s", ci->processor);
      g_free(ci->processor);
      ci->processor = proctemp;
    }
#endif

}

ComputerInfo *computer_get_info(void)
{
    gint i;
    struct stat st;
    ComputerInfo *ci;
    struct utsname utsbuf;

    ci = g_new0(ComputerInfo, 1);

    for (i = 0;; i++) {
      if (distro_db[i].file == NULL) {
          ci->distrocode = g_strdup("unk");
          ci->distroinfo = g_strdup(_("Unknown distribution"));
          break;
      }

      if (!stat(distro_db[i].file, &st)) {
          FILE *distro_ver;
          char buf[128];

          distro_ver = fopen(distro_db[i].file, "r");
          fgets(buf, 128, distro_ver);
          fclose(distro_ver);

          buf[strlen(buf) - 1] = 0;

          /*
           * HACK: Some Debian systems doesn't include
           * the distribuition name in /etc/debian_release,
           * so add them here. 
           */
          if (!strncmp(distro_db[i].codename, "deb", 3) &&
            ((buf[0] >= '0' && buf[0] <= '9') || buf[0] != 'D')) {
                  ci->distroinfo = g_strdup_printf
                      ("Debian GNU/Linux %s", buf);
          } else {
            ci->distroinfo = g_strdup(buf);
          }

          ci->distrocode = g_strdup(distro_db[i].codename);

          break;
      }
    }

    uname(&utsbuf);
    ci->kernel = g_strdup_printf("%s %s (%s)", utsbuf.sysname,
                         utsbuf.release, utsbuf.machine);

    ci->hostname = g_strdup(utsbuf.nodename);

    computer_processor_info(ci);

    return ci;
}

/*
 * Code stolen from GKrellM <http://www.gkrellm.net>
 * Copyright (c) 1999-2002 Bill Wilson <bill@gkrellm.net>
 */
gboolean uptime_update(gpointer data)
{
    MainWindow *mainwindow = (MainWindow *) data;
    gchar *buf;
    gint days, hours;
    FILE *procuptime;
    gulong minutes = 0;

    if (!mainwindow)
      return FALSE;

#define plural(a) (a == 1) ? "" : "s"

    if ((procuptime = fopen("/proc/uptime", "r")) != NULL) {
      fscanf(procuptime, "%lu", &minutes);
      minutes /= 60;
      fclose(procuptime);
    } else
      return FALSE;

    hours = minutes / 60;
    minutes %= 60;
    days = hours / 24;
    hours %= 24;

    if (days < 1) {
      buf = g_strdup_printf(_("%d hour%s and %ld minute%s"), hours,
                        plural(hours), minutes, plural(minutes));
    } else {
      buf =
          g_strdup_printf(_("%d day%s, %d hour%s and %ld minute%s"),
                      days, plural(days), hours, plural(hours),
                      minutes, plural(minutes));
    }

    gtk_label_set_text(GTK_LABEL(mainwindow->uptime), buf);
    g_free(buf);

    return TRUE;
}

GtkWidget *os_get_widget(MainWindow * mainwindow)
{
    GtkWidget *label, *hbox;
    GtkWidget *table;
    GtkWidget *pixmap;
    gchar *buf;
    ComputerInfo *info;

    if (!mainwindow)
      return NULL;

    info = computer_get_info();

    hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(hbox);

    buf =
      g_strdup_printf("%s/distro/%s.png", IMG_PREFIX, info->distrocode);
    pixmap = gtk_image_new_from_file(buf);
    gtk_widget_set_usize(GTK_WIDGET(pixmap), 64, 0);
    gtk_widget_show(pixmap);
    gtk_box_pack_start(GTK_BOX(hbox), pixmap, FALSE, FALSE, 0);
    g_free(buf);

    table = gtk_table_new(4, 2, FALSE);
    gtk_widget_show(table);
    gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(table), 10);
    gtk_table_set_row_spacings(GTK_TABLE(table), 4);
    gtk_table_set_col_spacings(GTK_TABLE(table), 4);

    /*
     * Table headers
     */
    label = gtk_label_new(_("<b>Computer name:</b>"));
    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(_("<b>Distribution:</b>"));
    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(_("<b>Kernel:</b>"));
    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(_("<b>Uptime:</b>"));
    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);


    /*
     * Table content 
     */
    label = gtk_label_new(info->hostname);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(info->distroinfo);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(info->kernel);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    label = gtk_label_new(_("Updating..."));
    gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 3, 4);
    gtk_widget_show(label);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    mainwindow->uptime = label;

    uptime_update(mainwindow);
    gtk_timeout_add(30000, uptime_update, mainwindow);

    g_free(info);

    return hbox;
}

gboolean memory_update(gpointer data)
{
    MainWindow *mainwindow = (MainWindow *) data;
    MemoryInfo *mi;

    if (!mainwindow)
      return FALSE;

    mi = memory_get_info();

    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(mainwindow->membar),
                          mi->ratio);

    g_free(mi);

    return TRUE;
}

GtkWidget *memory_get_widget(MainWindow * mainwindow)
{
    GtkWidget *label, *vbox, *hbox, *hbox2, *progress;
    GtkWidget *pixmap;
    MemoryInfo *mi;
    gchar *buf;

    mi = memory_get_info();

    hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(hbox);

    buf = g_strdup_printf("%s/mem.png", IMG_PREFIX);
    pixmap = gtk_image_new_from_file(buf);
    gtk_widget_set_usize(GTK_WIDGET(pixmap), 64, 0);
    gtk_widget_show(pixmap);
    gtk_box_pack_start(GTK_BOX(hbox), pixmap, FALSE, FALSE, 0);
    g_free(buf);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_widget_show(vbox);
    gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
    gtk_box_set_spacing(GTK_BOX(vbox), 4);

    hbox2 = gtk_hbox_new(FALSE, 5);
    gtk_widget_show(hbox2);
    gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);

    label = gtk_label_new("0MB");
    gtk_widget_show(label);
    gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);

    buf = g_strdup_printf("%dMB", mi->total);
    label = gtk_label_new(buf);
    gtk_widget_show(label);
    gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    g_free(buf);

    progress = gtk_progress_bar_new();
    mainwindow->membar = progress;
    gtk_widget_show(progress);
    gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 0);

    memory_update(mainwindow);

    gtk_timeout_add(2000, memory_update, mainwindow);

    g_free(mi);
    return hbox;
}

GtkWidget *processor_get_widget(void)
{
    GtkWidget *label, *vbox, *hbox;
    GtkWidget *pixmap;
    ComputerInfo *info;
    gchar *buf;

    info = computer_get_info();

    hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(hbox);

    buf = g_strdup_printf("%s/cpu.png", IMG_PREFIX);
    pixmap = gtk_image_new_from_file(buf);
    gtk_widget_set_usize(GTK_WIDGET(pixmap), 64, 0);
    gtk_widget_show(pixmap);
    gtk_box_pack_start(GTK_BOX(hbox), pixmap, FALSE, FALSE, 0);
    g_free(buf);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_widget_show(vbox);
    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
    gtk_box_set_spacing(GTK_BOX(vbox), 4);

    buf = g_strdup_printf(_("<b>%s</b> at %d MHz"),
                    info->processor, info->frequency);

    label = gtk_label_new(buf);
    gtk_widget_show(label);
    gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    g_free(buf);

#ifdef ARCH_i386
    buf = g_strdup_printf(_("Family %d, model %d, stepping %d"),
                    info->family, info->model, info->stepping);
    label = gtk_label_new(buf);
    gtk_widget_show(label);
    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    g_free(buf);
#endif

    if (info->cachel2) {
      buf = g_strdup_printf(_("%d KB L2 cache"), info->cachel2);
      label = gtk_label_new(buf);
      gtk_widget_show(label);

      gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
      g_free(buf);
    }

    g_free(info);
    return hbox;
}

Generated by  Doxygen 1.6.0   Back to index