/* * Distribuition detection routines * Copyright (c) 2003 Leandro Pereira * * May be distributed under the terms of GNU General Public License version 2. */ #include "hardinfo.h" #include "computer.h" #include #include #include #include #include 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 #ifdef ARCH_IA64 #define PARSE_PROC_CPU() \ if(!strncmp(buf, "BogoMIPS", 8)) \ get_int_val(ci->bogomips) \ else if(!strncmp(buf, "vendor", 6)) \ get_str_val(ci->machine) \ else if(!strncmp(buf, "family", 6)) \ get_str_val(ci->processor) \ else if(!strncmp(buf, "cpu MHz", 7)) \ get_int_val(ci->frequency) #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 * Copyright (c) 1999-2002 Bill Wilson */ 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(_("Computer name:")); 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(_("Distribution:")); 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(_("Kernel:")); 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(_("Uptime:")); 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(_("%s 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; }