#include <unistd.h>
#include <limits.h>
#include <signal.h>
+#include <string.h>
#include <sys/param.h>
-#include <string.h>
+#include <sys/sysctl.h>
+#include <sys/sensors.h>
+#include <sys/ioctl.h>
+
+#include <machine/apmvar.h>
#include <glib/gprintf.h>
#include <glib-unix.h>
+/* #include <gtk/gtk.h> */
#include "hostnamed-gen.h"
#include "hostnamed.h"
+/* add any sysctl strings that suggest virtualization here */
+/* format: {
+ * (1) string to be matched against runtime machine's sysctl output.
+ * can be either the exact string or a substring contained
+ * within sysctl strings. no "guesses" here, a match should
+ * reliably indicate the chassis/icon.
+ *
+ * (2) string describing chassis type divulged by (1).
+ * must be one of "desktop", "laptop", "server",
+ * "tablet", "handset", "vm", "container" or NULL
+ * if only icon string can be ascertained. "vm" refers
+ * to operating systems running on baremetal hypervisors
+ * (hardware virtualization, like XEN) while "container"
+ * refers to OSs running on shared hypervisors like
+ * virtualbox or VMware. consider the distinction carefully
+ * as common virtualization software like KVM may share
+ * characteristics of both "vm" and "container" types.
+ *
+ * (3) string specifying icon to use. follows XDG icon spec.
+ * see http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
+ * for allowed strings.
+ *
+ * (4) chassis precedence bit. TRUE if (2) is defined and
+ * we're certain it is the proper string. FALSE in the
+ * circumstance (2) may be the correct string, unless
+ * a match with this bit set to TRUE overrides it.
+ * if (2) is NULL, this bit is inconsequential.
+ *
+ * (5) icon precedence bit. see previous definition.
+ * } */
+struct SYSCTL_LOOKUP_TABLE {
+ gchar *match_string;
+ gchar *chassis;
+ gchar *icon;
+ gboolean chassis_precedence;
+ gboolean icon_precedence;
+};
+
GPtrArray *hostnamed_freeable;
Hostname1 *hostnamed_interf;
guint bus_descriptor;
gboolean dbus_interface_exported; /* reliable because of gdbus operational guarantees */
+gchar *CHASSIS, *ICON;
+
+/* TODO no specific vm or laptop icon in gnome
+ * NOTE paravirtualization on xen is only available for linuxes right now
+ * dmesg on linux systems reveals xen and virtualization method (HVM or PVM)
+ * but we will worry about those later */
+const struct SYSCTL_LOOKUP_TABLE chassis_indicator_table[] =
+{
+ { "QEMU Virtual CPU", "container", NULL, FALSE, FALSE }, /* could be QEMU running in userspace or as part of KVM */
+ { "KVM", "vm", "drive-multidisk", FALSE, FALSE },
+ { "SmartDC HVM", "vm", "drive-multidisk", TRUE, TRUE }, /* oracle solaris kvm */
+ { "VirtualBox", "container", "drive-optical", TRUE, TRUE },
+ { "VMware, Inc.", "container", "drive-optical", TRUE, TRUE },
+ { "VMware Virtual Platform", "container", "drive-optical", TRUE, TRUE },
+ { "Parallels", "container", "drive-optical", TRUE, TRUE } /* need verification */
+};
+
+/* archs to check against when determining if machine is server */
+const gchar *server_archs[] = {
+ "hppa",
+ "sparc",
+ "sparc64"
+};
+
/* --- begin method/property/dbus signal code --- */
static gboolean
const gchar *
our_get_static_hostname() {
- gchar *pretty_hostname;
- gchar *ret;
+ const gchar *pretty_hostname;
+ const gchar *ret;
pretty_hostname = our_get_pretty_hostname();
if(g_strcmp0(pretty_hostname, "") == 0)
ret = our_get_hostname();
- else if(ret = g_hostname_to_ascii(pretty_hostname)) {
+ else if((ret = g_hostname_to_ascii(pretty_hostname))) {
- g_ptr_array_add(hostnamed_freeable, ret);
+ g_ptr_array_add(hostnamed_freeable, (gpointer)ret);
return ret;
}
GKeyFile *config;
gchar *ret;
+ config = g_key_file_new();
+
if(g_key_file_load_from_file(config, "/etc/systemd_compat.conf", G_KEY_FILE_NONE, NULL)
- && ret = g_key_file_get_value(config, "hostnamed", "PrettyHostname", NULL)) { /* ret might need to be freed, docs dont specify but i am suspicious */
+ && (ret = g_key_file_get_value(config, "hostnamed", "PrettyHostname", NULL))) { /* ret might need to be freed, docs dont specify but i am suspicious */
- g_free(config);
+ g_key_file_unref(config);
return ret;
}
const gchar *
our_get_chassis() {
- return "TODO";
+ if(CHASSIS)
+ return CHASSIS;
+
+ return "desktop";
}
const gchar *
our_get_icon_name() {
- return "TODO";
+ if(ICON)
+ return ICON;
+
+ return "";
}
const gchar *
}
int main() {
-
+
+ /* TODO: check for valid, writable config at init. if no, complain to `make install` */
+
set_signal_handlers();
- hostnamed_loop = g_main_loop_new(NULL, TRUE);
+ if(!determine_chassis_and_icon())
+ return 1;
+
+ hostnamed_loop = g_main_loop_new(NULL, TRUE);
hostnamed_freeable = g_ptr_array_new();
bus_descriptor = g_bus_own_name(G_BUS_TYPE_SYSTEM,
return 0;
}
-/* TODO figure out DMI variables on obsd */
-/*static gchar *guess_icon_name() {
+gboolean determine_chassis_and_icon() {
+
+ const size_t bufsize = 4096;
+
+ char *hwproduct, *hwmodel, *hwvendor, *hwmachine;
+ size_t hwproduct_size, hwmodel_size, hwvendor_size, hwmachine_size;
+ int hwproduct_name[2], hwmodel_name[2], hwvendor_name[2], hwmachine_name[2];
+ unsigned int i;
+ gboolean UNSURE_CHASSIS_FLAG, UNSURE_ICON_FLAG;
+
+ hwproduct_size = hwmodel_size = hwvendor_size = hwmachine_size = bufsize;
+ UNSURE_CHASSIS_FLAG = UNSURE_ICON_FLAG = FALSE;
+ i = 0;
+
+ hwproduct = (char*)g_malloc0(4096);
+ hwmodel = (char*)g_malloc0(4096);
+ hwvendor = (char*)g_malloc0(4096);
+ hwmachine = (char*)g_malloc0(4096);
+
+ hwproduct_name[0] = CTL_HW;
+ hwproduct_name[1] = HW_PRODUCT;
+
+ hwmodel_name[0] = CTL_HW;
+ hwmodel_name[1] = HW_MODEL;
+
+ hwvendor_name[0] = CTL_HW;
+ hwvendor_name[1] = HW_VENDOR;
+
+ hwmachine_name[0] = CTL_HW;
+ hwmachine_name[1] = HW_MACHINE;
+
+ /* pass NULL buffer to check size first, then pass hw to be filled according to freshly-set hw_size */
+ if(-1 == sysctl(hwproduct_name, 2, NULL, &hwproduct_size, NULL, 0) || -1 == sysctl(hwproduct_name, 2, hwproduct, &hwproduct_size, NULL, 0))
+ return FALSE;
+
+ if(-1 == sysctl(hwmodel_name, 2, NULL, &hwmodel_size, NULL, 0) || -1 == sysctl(hwmodel_name, 2, hwmodel, &hwmodel_size, NULL, 0))
+ return FALSE;
+
+ if(-1 == sysctl(hwvendor_name, 2, NULL, &hwvendor_size, NULL, 0) || -1 == sysctl(hwvendor_name, 2, hwvendor, &hwvendor_size, NULL, 0))
+ return FALSE;
+
+ if(-1 == sysctl(hwmachine_name, 2, NULL, &hwmachine_size, NULL, 0) || -1 == sysctl(hwmachine_name, 2, hwmachine, &hwmachine_size, NULL, 0))
+ return FALSE;
+
+ /* TODO: test for laptop, if not, dmidecode for desktop vs. server
+ * probably move this code to vm test func and set a global after running it early, once */
+
+ for(; i < G_N_ELEMENTS(chassis_indicator_table); i++) {
+ if(strcasestr(hwproduct, chassis_indicator_table[i].match_string)
+ || strcasestr(hwmodel, chassis_indicator_table[i].match_string)
+ || strcasestr(hwvendor, chassis_indicator_table[i].match_string)) {
+
+ if(!UNSURE_CHASSIS_FLAG && chassis_indicator_table[i].chassis) {
+
+ UNSURE_CHASSIS_FLAG = chassis_indicator_table[i].chassis_precedence;
+ CHASSIS = chassis_indicator_table[i].chassis;
+ }
+
+ if(!UNSURE_ICON_FLAG && chassis_indicator_table[i].icon) {
+
+ UNSURE_ICON_FLAG = chassis_indicator_table[i].icon_precedence;
+ ICON = chassis_indicator_table[i].icon;
+ }
+ }
+ }
+
+ if(up_native_is_laptop()) {
+
+ if(!CHASSIS)
+ CHASSIS = "laptop";
+ if(!ICON)
+ ICON = "input-touchpad"; /* TODO pull an icon package that actually has the icons we're looking for */
+
+ } else if(is_server(hwmachine)) {
+
+ if(!CHASSIS)
+ CHASSIS = "server";
+ if(!ICON)
+ ICON = "uninterruptible-power-supply";
- gchar *filebuf = NULL;
- gchar *ret = NULL;
+ } else if(!CHASSIS || !ICON) {
+
+ if(!CHASSIS)
+ CHASSIS = "desktop";
+ if(!ICON)
+ ICON = "computer";
+ }
+
+ return (CHASSIS && ICON);
+}
- #if defined(__i386__) || defined(__x86_64__)
+gboolean is_server(gchar *arch) {
- Taken with a few minor changes from systemd's hostnamed.c,
- copyright 2011 Lennart Poettering.
-
- See the SMBIOS Specification 2.7.1 section 7.4.1 for
- details about the values listed here:
-
- http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
-
-
- if (g_file_get_contents ("/sys/class/dmi/id/chassis_type", &filebuf, NULL, NULL)) {
- switch (g_ascii_strtoull (filebuf, NULL, 10)) {
- case 0x3:
- case 0x4:
- case 0x5:
- case 0x6:
- case 0x7:
- ret = g_strdup ("computer-desktop");
- goto out;
- case 0x9:
- case 0xA:
- case 0xE:
- ret = g_strdup ("computer-laptop");
- goto out;
- case 0x11:
- case 0x17:
- case 0x1C:
- case 0x1D:
- ret = g_strdup ("computer-server");
- goto out;
+ unsigned int i;
+
+ for(; i < G_N_ELEMENTS(server_archs); i++)
+ if(strcasestr(arch, server_archs[i]))
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean up_native_is_laptop() {
+
+ struct apm_power_info bstate;
+ struct sensordev acpiac;
+
+ if (up_native_get_sensordev("acpiac0", &acpiac))
+ return TRUE;
+
+ if (-1 == ioctl(up_apm_get_fd(), APM_IOC_GETPOWER, &bstate))
+ g_error("ioctl on apm fd failed : %s", g_strerror(errno));
+
+ return bstate.ac_state != APM_AC_UNKNOWN;
+}
+
+int up_apm_get_fd() {
+
+ static int apm_fd = 0;
+
+ if(apm_fd == 0) {
+
+ g_debug("apm_fd is not initialized yet, opening");
+
+ /* open /dev/apm */
+ if((apm_fd = open("/dev/apm", O_RDONLY)) == -1) {
+ if(errno != ENXIO && errno != ENOENT)
+ g_error("cannot open device file");
}
}
- #endif
- ret = g_strdup ("computer");
- out:
- g_free (filebuf);
- return ret;
-}*/
+ return apm_fd;
+}
+
+gboolean up_native_get_sensordev(const char * id, struct sensordev * snsrdev) {
+
+ int devn;
+ size_t sdlen = sizeof(struct sensordev);
+ int mib[] = {CTL_HW, HW_SENSORS, 0, 0 ,0};
+
+ for (devn = 0 ; ; devn++) {
+ mib[2] = devn;
+ if(sysctl(mib, 3, snsrdev, &sdlen, NULL, 0) == -1) {
+ if(errno == ENXIO)
+ continue;
+ if(errno == ENOENT)
+ break;
+ }
+
+ if (!strcmp(snsrdev->xname, id))
+ return TRUE;
+ }
+
+ return FALSE;
+}