summaryrefslogtreecommitdiff
path: root/src/freebsd
diff options
context:
space:
mode:
authorJoe Marcus Clarke <marcus@FreeBSD.org>2010-01-02 14:03:05 -0500
committerRichard Hughes <richard@hughsie.com>2010-01-03 08:54:30 +0000
commit131bc12a81855a30cc300dff237ac78f803e595f (patch)
tree2b5a1536f64f845c18e5cf78903874060f14c059 /src/freebsd
parent725acd4d354c27eb5828e8d6e388ecf34a7c6303 (diff)
downloadupower-131bc12a81855a30cc300dff237ac78f803e595f.tar.gz
import the FreeBSD backend
Add a backend for FreeBSD supporting AC power lines, batteries, and lid state.
Diffstat (limited to 'src/freebsd')
-rw-r--r--src/freebsd/Makefile.am45
-rw-r--r--src/freebsd/TODO4
-rw-r--r--src/freebsd/dkp-acpi-native.c234
-rw-r--r--src/freebsd/dkp-acpi-native.h48
-rw-r--r--src/freebsd/dkp-acpi-native.vala46
-rw-r--r--src/freebsd/dkp-backend-acpi.h33
-rw-r--r--src/freebsd/dkp-backend.c511
-rw-r--r--src/freebsd/dkp-devd.c245
-rw-r--r--src/freebsd/dkp-devd.h46
-rw-r--r--src/freebsd/dkp-device-supply.c544
-rw-r--r--src/freebsd/dkp-device-supply.h56
-rw-r--r--src/freebsd/dkp-native.c66
-rw-r--r--src/freebsd/dkp-util.c145
-rw-r--r--src/freebsd/dkp-util.h50
14 files changed, 2073 insertions, 0 deletions
diff --git a/src/freebsd/Makefile.am b/src/freebsd/Makefile.am
new file mode 100644
index 0000000..32016bb
--- /dev/null
+++ b/src/freebsd/Makefile.am
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = \
+ -I$(top_builddir)/src -I$(top_srcdir)/src \
+ -DEGG_LOG_FILE=\""$(DKP_LOG_DIR)/DeviceKit-power"\" \
+ -DEGG_VERBOSE="\"DKP_VERBOSE\"" \
+ -DEGG_LOGGING="\"DKP_LOGGING\"" \
+ -DEGG_CONSOLE="\"DKP_CONSOLE\"" \
+ -DDKP_COMPILATION \
+ -I$(top_srcdir)/devkit-power-gobject \
+ $(DBUS_GLIB_CFLAGS) \
+ $(POLKIT_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+if BACKEND_TYPE_FREEBSD
+noinst_LTLIBRARIES = libdkpshared.la
+endif
+
+libdkpshared_la_SOURCES = \
+ dkp-acpi-native.c \
+ dkp-acpi-native.h \
+ dkp-backend-acpi.h \
+ dkp-backend.c \
+ dkp-devd.c \
+ dkp-devd.h \
+ dkp-device-supply.c \
+ dkp-device-supply.h \
+ dkp-native.c \
+ dkp-util.c \
+ dkp-util.h \
+ $(BUILT_SOURCES)
+
+libdkpshared_la_CFLAGS = \
+ $(WARNINGFLAGS_C)
+
+libdkpshared_la_LIBADD = \
+ -lkvm
+
+EXTRA_DIST = \
+ dkp-acpi-native.vala \
+ TODO
+
+clean-local :
+ rm -f *~
+
diff --git a/src/freebsd/TODO b/src/freebsd/TODO
new file mode 100644
index 0000000..4e1b72b
--- /dev/null
+++ b/src/freebsd/TODO
@@ -0,0 +1,4 @@
+FreeBSD doesn't have udev, so the udev rules can't be automatically applied.
+However, they are useful in that they contain some needed battery recall
+information. To that end, they should be incorporated into the FreeBSD
+backend probably by adding them to a static array, or a hashtable.
diff --git a/src/freebsd/dkp-acpi-native.c b/src/freebsd/dkp-acpi-native.c
new file mode 100644
index 0000000..71ff1b2
--- /dev/null
+++ b/src/freebsd/dkp-acpi-native.c
@@ -0,0 +1,234 @@
+/* dkp-acpi-native.c generated by valac, the Vala compiler
+ * generated from dkp-acpi-native.vala, do not modify */
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define TYPE_DKP_ACPI_NATIVE (dkp_acpi_native_get_type ())
+#define DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNative))
+#define DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
+#define IS_DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_DKP_ACPI_NATIVE))
+#define IS_DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DKP_ACPI_NATIVE))
+#define DKP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
+
+typedef struct _DkpAcpiNative DkpAcpiNative;
+typedef struct _DkpAcpiNativeClass DkpAcpiNativeClass;
+typedef struct _DkpAcpiNativePrivate DkpAcpiNativePrivate;
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
+#define _g_match_info_free0(var) ((var == NULL) ? NULL : (var = (g_match_info_free (var), NULL)))
+#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
+
+struct _DkpAcpiNative {
+ GObject parent_instance;
+ DkpAcpiNativePrivate * priv;
+};
+
+struct _DkpAcpiNativeClass {
+ GObjectClass parent_class;
+};
+
+struct _DkpAcpiNativePrivate {
+ char* _driver;
+ gint _unit;
+ char* _path;
+};
+
+
+static gpointer dkp_acpi_native_parent_class = NULL;
+
+GType dkp_acpi_native_get_type (void);
+#define DKP_ACPI_NATIVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativePrivate))
+enum {
+ DKP_ACPI_NATIVE_DUMMY_PROPERTY,
+ DKP_ACPI_NATIVE_DRIVER,
+ DKP_ACPI_NATIVE_UNIT,
+ DKP_ACPI_NATIVE_PATH
+};
+DkpAcpiNative* dkp_acpi_native_new (const char* path);
+DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path);
+DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit);
+DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit);
+const char* dkp_acpi_native_get_driver (DkpAcpiNative* self);
+gint dkp_acpi_native_get_unit (DkpAcpiNative* self);
+const char* dkp_acpi_native_get_path (DkpAcpiNative* self);
+static void dkp_acpi_native_finalize (GObject* obj);
+static void dkp_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec);
+
+
+
+DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path) {
+ GError * _inner_error_;
+ DkpAcpiNative * self;
+ GRegex* r;
+ GMatchInfo* mi;
+ gboolean ret = FALSE;
+ char* _tmp9_;
+ g_return_val_if_fail (path != NULL, NULL);
+ _inner_error_ = NULL;
+ self = (DkpAcpiNative*) g_object_new (object_type, NULL);
+ r = NULL;
+ mi = NULL;
+ {
+ GRegex* _tmp0_;
+ GRegex* _tmp1_;
+ GMatchInfo* _tmp4_;
+ gboolean _tmp3_;
+ GMatchInfo* _tmp2_ = NULL;
+ _tmp0_ = g_regex_new ("dev\\.([^\\.])\\.(\\d+)", 0, 0, &_inner_error_);
+ if (_inner_error_ != NULL) {
+ if (_inner_error_->domain == G_REGEX_ERROR) {
+ goto __catch0_g_regex_error;
+ }
+ goto __finally0;
+ }
+ r = (_tmp1_ = _tmp0_, _g_regex_unref0 (r), _tmp1_);
+ ret = (_tmp3_ = g_regex_match (r, path, 0, &_tmp2_), mi = (_tmp4_ = _tmp2_, _g_match_info_free0 (mi), _tmp4_), _tmp3_);
+ if (ret) {
+ char* _tmp5_;
+ char* _tmp6_;
+ self->priv->_driver = (_tmp5_ = g_match_info_fetch (mi, 1), _g_free0 (self->priv->_driver), _tmp5_);
+ self->priv->_unit = atoi (_tmp6_ = g_match_info_fetch (mi, 2));
+ _g_free0 (_tmp6_);
+ } else {
+ char* _tmp7_;
+ self->priv->_driver = (_tmp7_ = NULL, _g_free0 (self->priv->_driver), _tmp7_);
+ self->priv->_unit = -1;
+ }
+ }
+ goto __finally0;
+ __catch0_g_regex_error:
+ {
+ GError * re;
+ re = _inner_error_;
+ _inner_error_ = NULL;
+ {
+ char* _tmp8_;
+ self->priv->_driver = (_tmp8_ = NULL, _g_free0 (self->priv->_driver), _tmp8_);
+ self->priv->_unit = -1;
+ _g_error_free0 (re);
+ }
+ }
+ __finally0:
+ if (_inner_error_ != NULL) {
+ _g_regex_unref0 (r);
+ _g_match_info_free0 (mi);
+ g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+ g_clear_error (&_inner_error_);
+ return NULL;
+ }
+ self->priv->_path = (_tmp9_ = g_strdup (path), _g_free0 (self->priv->_path), _tmp9_);
+ _g_regex_unref0 (r);
+ _g_match_info_free0 (mi);
+ return self;
+}
+
+
+DkpAcpiNative* dkp_acpi_native_new (const char* path) {
+ return dkp_acpi_native_construct (TYPE_DKP_ACPI_NATIVE, path);
+}
+
+
+DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit) {
+ DkpAcpiNative * self;
+ char* _tmp0_;
+ char* _tmp1_;
+ g_return_val_if_fail (driver != NULL, NULL);
+ self = (DkpAcpiNative*) g_object_new (object_type, NULL);
+ self->priv->_driver = (_tmp0_ = g_strdup (driver), _g_free0 (self->priv->_driver), _tmp0_);
+ self->priv->_unit = unit;
+ self->priv->_path = (_tmp1_ = g_strdup_printf ("dev.%s.%i", self->priv->_driver, self->priv->_unit), _g_free0 (self->priv->_path), _tmp1_);
+ return self;
+}
+
+
+DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit) {
+ return dkp_acpi_native_construct_driver_unit (TYPE_DKP_ACPI_NATIVE, driver, unit);
+}
+
+
+const char* dkp_acpi_native_get_driver (DkpAcpiNative* self) {
+ const char* result;
+ g_return_val_if_fail (self != NULL, NULL);
+ result = self->priv->_driver;
+ return result;
+}
+
+
+gint dkp_acpi_native_get_unit (DkpAcpiNative* self) {
+ gint result;
+ g_return_val_if_fail (self != NULL, 0);
+ result = self->priv->_unit;
+ return result;
+}
+
+
+const char* dkp_acpi_native_get_path (DkpAcpiNative* self) {
+ const char* result;
+ g_return_val_if_fail (self != NULL, NULL);
+ result = self->priv->_path;
+ return result;
+}
+
+
+static void dkp_acpi_native_class_init (DkpAcpiNativeClass * klass) {
+ dkp_acpi_native_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (DkpAcpiNativePrivate));
+ G_OBJECT_CLASS (klass)->get_property = dkp_acpi_native_get_property;
+ G_OBJECT_CLASS (klass)->finalize = dkp_acpi_native_finalize;
+ g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_DRIVER, g_param_spec_string ("driver", "driver", "driver", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_UNIT, g_param_spec_int ("unit", "unit", "unit", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), DKP_ACPI_NATIVE_PATH, g_param_spec_string ("path", "path", "path", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
+}
+
+
+static void dkp_acpi_native_instance_init (DkpAcpiNative * self) {
+ self->priv = DKP_ACPI_NATIVE_GET_PRIVATE (self);
+}
+
+
+static void dkp_acpi_native_finalize (GObject* obj) {
+ DkpAcpiNative * self;
+ self = DKP_ACPI_NATIVE (obj);
+ _g_free0 (self->priv->_driver);
+ _g_free0 (self->priv->_path);
+ G_OBJECT_CLASS (dkp_acpi_native_parent_class)->finalize (obj);
+}
+
+
+GType dkp_acpi_native_get_type (void) {
+ static GType dkp_acpi_native_type_id = 0;
+ if (dkp_acpi_native_type_id == 0) {
+ static const GTypeInfo g_define_type_info = { sizeof (DkpAcpiNativeClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) dkp_acpi_native_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DkpAcpiNative), 0, (GInstanceInitFunc) dkp_acpi_native_instance_init, NULL };
+ dkp_acpi_native_type_id = g_type_register_static (G_TYPE_OBJECT, "DkpAcpiNative", &g_define_type_info, 0);
+ }
+ return dkp_acpi_native_type_id;
+}
+
+
+static void dkp_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
+ DkpAcpiNative * self;
+ self = DKP_ACPI_NATIVE (object);
+ switch (property_id) {
+ case DKP_ACPI_NATIVE_DRIVER:
+ g_value_set_string (value, dkp_acpi_native_get_driver (self));
+ break;
+ case DKP_ACPI_NATIVE_UNIT:
+ g_value_set_int (value, dkp_acpi_native_get_unit (self));
+ break;
+ case DKP_ACPI_NATIVE_PATH:
+ g_value_set_string (value, dkp_acpi_native_get_path (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+
+
diff --git a/src/freebsd/dkp-acpi-native.h b/src/freebsd/dkp-acpi-native.h
new file mode 100644
index 0000000..987e330
--- /dev/null
+++ b/src/freebsd/dkp-acpi-native.h
@@ -0,0 +1,48 @@
+/* dkp-acpi-native.h generated by valac, the Vala compiler, do not modify */
+
+
+#ifndef __DKP_ACPI_NATIVE_H__
+#define __DKP_ACPI_NATIVE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <stdlib.h>
+#include <string.h>
+
+G_BEGIN_DECLS
+
+
+#define TYPE_DKP_ACPI_NATIVE (dkp_acpi_native_get_type ())
+#define DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNative))
+#define DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
+#define IS_DKP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_DKP_ACPI_NATIVE))
+#define IS_DKP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DKP_ACPI_NATIVE))
+#define DKP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DKP_ACPI_NATIVE, DkpAcpiNativeClass))
+
+typedef struct _DkpAcpiNative DkpAcpiNative;
+typedef struct _DkpAcpiNativeClass DkpAcpiNativeClass;
+typedef struct _DkpAcpiNativePrivate DkpAcpiNativePrivate;
+
+struct _DkpAcpiNative {
+ GObject parent_instance;
+ DkpAcpiNativePrivate * priv;
+};
+
+struct _DkpAcpiNativeClass {
+ GObjectClass parent_class;
+};
+
+
+GType dkp_acpi_native_get_type (void);
+DkpAcpiNative* dkp_acpi_native_new (const char* path);
+DkpAcpiNative* dkp_acpi_native_construct (GType object_type, const char* path);
+DkpAcpiNative* dkp_acpi_native_new_driver_unit (const char* driver, gint unit);
+DkpAcpiNative* dkp_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit);
+const char* dkp_acpi_native_get_driver (DkpAcpiNative* self);
+gint dkp_acpi_native_get_unit (DkpAcpiNative* self);
+const char* dkp_acpi_native_get_path (DkpAcpiNative* self);
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/freebsd/dkp-acpi-native.vala b/src/freebsd/dkp-acpi-native.vala
new file mode 100644
index 0000000..7710798
--- /dev/null
+++ b/src/freebsd/dkp-acpi-native.vala
@@ -0,0 +1,46 @@
+public class DkpAcpiNative : Object {
+ private string? _driver;
+ private int _unit;
+ private string _path;
+
+ public string driver {
+ get { return _driver; }
+ }
+
+ public int unit {
+ get { return _unit; }
+ }
+
+ public string path {
+ get { return _path; }
+ }
+
+ public DkpAcpiNative (string path) {
+ Regex r;
+ MatchInfo mi;
+ bool ret;
+
+ try {
+ r = new Regex("dev\\.([^\\.])\\.(\\d+)");
+ ret = r.match(path, 0, out mi);
+ if (ret) {
+ _driver = mi.fetch(1);
+ _unit = mi.fetch(2).to_int();
+ } else {
+ _driver = null;
+ _unit = -1;
+ }
+ } catch (RegexError re) {
+ _driver = null;
+ _unit = -1;
+ }
+
+ _path = path;
+ }
+
+ public DkpAcpiNative.driver_unit (string driver, int unit) {
+ _driver = driver;
+ _unit = unit;
+ _path = "dev.%s.%i".printf (_driver, _unit);
+ }
+}
diff --git a/src/freebsd/dkp-backend-acpi.h b/src/freebsd/dkp-backend-acpi.h
new file mode 100644
index 0000000..d351f81
--- /dev/null
+++ b/src/freebsd/dkp-backend-acpi.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * dkp-backend-acpi.h : define some backend objects
+ *
+ * Copyright (C) 2006, 2009 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef _DKP_BACKEND_ACPI_H
+#define _DKP_BACKEND_ACPI_H
+
+#include "config.h"
+
+#include "dkp-devd.h"
+
+extern DkpDevdHandler dkp_backend_acpi_devd_handler;
+
+#endif /* _DKP_BACKEND_ACPI_H */
diff --git a/src/freebsd/dkp-backend.c b/src/freebsd/dkp-backend.c
new file mode 100644
index 0000000..55f0c32
--- /dev/null
+++ b/src/freebsd/dkp-backend.c
@@ -0,0 +1,511 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <kvm.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "dkp-acpi-native.h"
+#include "dkp-backend-acpi.h"
+#include "dkp-devd.h"
+#include "dkp-device-supply.h"
+#include "dkp-util.h"
+
+#include "egg-debug.h"
+
+#include "dkp-backend.h"
+#include "dkp-daemon.h"
+#include "dkp-marshal.h"
+#include "dkp-device.h"
+
+#define DKP_BACKEND_REFRESH_TIMEOUT 30 /* seconds */
+#define DKP_BACKEND_SUSPEND_COMMAND "/usr/sbin/zzz"
+#define DKP_BACKEND_HIBERNATE_COMMAND "/usr/sbin/acpiconf -s 4"
+
+static void dkp_backend_class_init (DkpBackendClass *klass);
+static void dkp_backend_init (DkpBackend *backend);
+static void dkp_backend_finalize (GObject *object);
+
+static gboolean dkp_backend_refresh_devices (gpointer user_data);
+static gboolean dkp_backend_acpi_devd_notify (DkpBackend *backend, const char *system, const char *subsystem, const char *type, const char *data);
+static gboolean dkp_backend_create_new_device (DkpBackend *backend, DkpAcpiNative *native);
+static void dkp_backend_lid_coldplug (DkpBackend *backend);
+static gboolean dkp_backend_supports_sleep_state (const char *state);
+
+#define DKP_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DKP_TYPE_BACKEND, DkpBackendPrivate))
+
+struct DkpBackendPrivate
+{
+ DkpDaemon *daemon;
+ DkpDeviceList *device_list;
+ GHashTable *handle_map;
+ guint poll_timer_id;
+};
+
+enum {
+ SIGNAL_DEVICE_ADDED,
+ SIGNAL_DEVICE_REMOVED,
+ SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE (DkpBackend, dkp_backend, G_TYPE_OBJECT)
+
+static const char *handlers[] = {
+ "battery",
+};
+
+DkpDevdHandler dkp_backend_acpi_devd_handler = {
+ .notify = dkp_backend_acpi_devd_notify
+};
+
+/**
+ * dkp_backend_refresh_devices:
+ **/
+static gboolean
+dkp_backend_refresh_devices (gpointer user_data)
+{
+ DkpBackend *backend;
+ GPtrArray *array;
+ DkpDevice *device;
+ guint i;
+
+ backend = DKP_BACKEND (user_data);
+ array = dkp_device_list_get_array (backend->priv->device_list);
+
+ for (i = 0; i < array->len; i++) {
+ device = DKP_DEVICE (g_ptr_array_index (array, i));
+ dkp_device_refresh_internal (device);
+ }
+
+ g_ptr_array_unref (array);
+
+ return TRUE;
+}
+
+/**
+ * dkp_backend_acpi_devd_notify:
+ **/
+static gboolean
+dkp_backend_acpi_devd_notify (DkpBackend *backend, const char *system, const char *subsystem, const char *type, const char *data)
+{
+ GObject *object = NULL;
+ DkpAcpiNative *native = NULL;
+
+ if (strcmp (system, "ACPI"))
+ return FALSE;
+
+ if (!strcmp (subsystem, "ACAD")) {
+ native = dkp_acpi_native_new ("hw.acpi.acline");
+ object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
+ } else if (!strcmp (subsystem, "CMBAT")) {
+ char *ptr;
+ int unit;
+
+ ptr = strstr (type, ".BAT");
+
+ if (ptr != NULL && sscanf (ptr, ".BAT%i", &unit)) {
+ native = dkp_acpi_native_new_driver_unit ("battery", unit);
+ object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
+ if (object == NULL) {
+ gpointer hptr;
+
+ hptr = g_hash_table_lookup (backend->priv->handle_map, type);
+ if (hptr != NULL) {
+ object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (hptr));
+ }
+ }
+ }
+ } else if (!strcmp (subsystem, "Lid")) {
+ gboolean is_present;
+ gboolean is_closed;
+
+ g_object_get (backend->priv->daemon,
+ "lid-is-present", &is_present, NULL);
+ if (!is_present) {
+ egg_warning ("received lid event without a configured lid; cold-plugging one");
+ dkp_backend_lid_coldplug (backend);
+ /* FALLTHROUGH */
+ }
+
+ is_closed = (data != NULL && !strcmp (data, "notify=0x00")) ?
+ TRUE : FALSE;
+ g_object_set (backend->priv->daemon, "lid-is-closed", is_closed, NULL);
+ goto out;
+ }
+
+ if (native == NULL)
+ goto out;
+
+ if (object == NULL) {
+ egg_warning ("did not find existing %s device; cold-plugging a new one", subsystem);
+ dkp_backend_create_new_device (backend, native);
+ goto out;
+ }
+
+ dkp_device_refresh_internal (DKP_DEVICE (object));
+
+ if (object != NULL)
+ g_object_unref (object);
+out:
+ if (native != NULL)
+ g_object_unref (native);
+
+ return TRUE;
+}
+
+/**
+ * dkp_backend_create_new_device:
+ **/
+static gboolean
+dkp_backend_create_new_device (DkpBackend *backend, DkpAcpiNative *native)
+{
+ DkpDevice *device;
+ gboolean ret;
+
+ device = DKP_DEVICE (dkp_device_supply_new ());
+ ret = dkp_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
+ if (!ret)
+ g_object_unref (device);
+ else {
+ if (!strncmp (dkp_acpi_native_get_path (native), "dev.", strlen ("dev."))) {
+ const char *path;
+
+ path = dkp_acpi_native_get_path (native);
+ if (dkp_has_sysctl ("%s.%%location", path)) {
+ char *location;
+
+ location = dkp_get_string_sysctl (NULL, "%s.%%location", path);
+ if (location != NULL && strstr (location, "handle=") != NULL) {
+ char *handle;
+
+ handle = strstr (location, "handle=");
+ handle += strlen ("handle=");
+ g_hash_table_insert (backend->priv->handle_map, g_strdup (handle), g_object_ref (native));
+ }
+ g_free (location);
+ }
+ }
+
+ g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, native, device);
+ }
+
+ return ret;
+}
+
+/**
+ * dkp_backend_lid_coldplug:
+ **/
+static void
+dkp_backend_lid_coldplug (DkpBackend *backend)
+{
+ char *lid_state;
+
+ lid_state = dkp_get_string_sysctl (NULL, "hw.acpi.lid_switch_state");
+ if (lid_state && strcmp (lid_state, "NONE")) {
+ g_object_set (backend->priv->daemon, "lid-is-present", TRUE, NULL);
+ }
+ g_free (lid_state);
+}
+
+
+/**
+ * dkp_backend_coldplug:
+ * @backend: The %DkpBackend class instance
+ * @daemon: The %DkpDaemon controlling instance
+ *
+ * Finds all the devices already plugged in, and emits device-add signals for
+ * each of them.
+ *
+ * Return value: %TRUE for success
+ **/
+gboolean
+dkp_backend_coldplug (DkpBackend *backend, DkpDaemon *daemon)
+{
+ DkpAcpiNative *acnative;
+ int i;
+
+ backend->priv->daemon = g_object_ref (daemon);
+ backend->priv->device_list = dkp_daemon_get_device_list (daemon);
+
+ for (i = 0; i < (int) G_N_ELEMENTS (handlers); i++) {
+ int j;
+
+ for (j = 0; dkp_has_sysctl ("dev.%s.%i.%%driver", handlers[i], j); j++) {
+ DkpAcpiNative *native;
+ DkpDevice *device;
+ GObject *object;
+
+ native = dkp_acpi_native_new_driver_unit (handlers[i], j);
+ object = dkp_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
+ if (object != NULL) {
+ device = DKP_DEVICE (object);
+ egg_warning ("treating add event as change event on %s", dkp_device_get_object_path (device));
+ dkp_device_refresh_internal (device);
+ } else {
+ dkp_backend_create_new_device (backend, native);
+ }
+
+ if (object != NULL) {
+ g_object_unref (object);
+ }
+ if (native != NULL) {
+ g_object_unref (native);
+ }
+ }
+ }
+
+ dkp_backend_lid_coldplug (backend);
+
+ acnative = dkp_acpi_native_new ("hw.acpi.acline");
+ dkp_backend_create_new_device (backend, acnative);
+ g_object_unref (acnative);
+
+ dkp_devd_init (backend);
+
+ backend->priv->poll_timer_id =
+ g_timeout_add_seconds (DKP_BACKEND_REFRESH_TIMEOUT,
+ (GSourceFunc) dkp_backend_refresh_devices,
+ backend);
+
+ return TRUE;
+}
+
+/**
+ * dkp_backend_get_powersave_command:
+ **/
+gchar *
+dkp_backend_get_powersave_command (DkpBackend *backend, gboolean powersave)
+{
+ /* XXX: Do we want to use powerd here? */
+ return NULL;
+}
+
+/**
+ * dkp_backend_get_suspend_command:
+ **/
+gchar *
+dkp_backend_get_suspend_command (DkpBackend *backend)
+{
+ return g_strdup (DKP_BACKEND_SUSPEND_COMMAND);
+}
+
+/**
+ * dkp_backend_get_hibernate_command:
+ **/
+gchar *
+dkp_backend_get_hibernate_command (DkpBackend *backend)
+{
+ return g_strdup (DKP_BACKEND_HIBERNATE_COMMAND);
+}
+
+/**
+ * dkp_backend_can_suspend:
+ **/
+gboolean
+dkp_backend_can_suspend (DkpBackend *backend)
+{
+ return dkp_backend_supports_sleep_state ("S3");
+}
+
+/**
+ * dkp_backend_can_hibernate:
+ **/
+gboolean
+dkp_backend_can_hibernate (DkpBackend *backend)
+{
+ return dkp_backend_supports_sleep_state ("S4");
+}
+
+gboolean
+dkp_backend_has_encrypted_swap (DkpBackend *backend)
+{
+ /* XXX: Add support for GELI? */
+ return FALSE;
+}
+
+gfloat
+dkp_backend_get_used_swap (DkpBackend *backend)
+{
+ gfloat percent;
+ kvm_t *kd;
+ char errbuf[_POSIX2_LINE_MAX];
+ int nswdev;
+ struct kvm_swap kvmsw[16];
+
+ kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == NULL) {
+ egg_warning ("failed to open kvm: '%s'", errbuf);
+ return 0.0f;
+ }
+
+ nswdev = kvm_getswapinfo (kd, kvmsw, 16, 0);
+ if (nswdev == 0) {
+ percent = 100.0f;
+ goto out;
+ }
+ if (nswdev < 0) {
+ egg_warning ("failed to get swap info: '%s'", kvm_geterr (kd));
+ percent = 0.0f;
+ goto out;
+ }
+
+ percent = (gfloat) ((gfloat) ((gfloat) kvmsw[nswdev].ksw_used / (gfloat) kvmsw[nswdev].ksw_total) * 100.0f);
+
+out:
+ kvm_close (kd);
+
+ return percent;
+}
+
+/**
+ * dkp_backend_supports_sleep_state:
+ **/
+static gboolean
+dkp_backend_supports_sleep_state (const char *state)
+{
+ char *sleep_states;
+ gboolean ret = FALSE;
+
+ sleep_states = dkp_get_string_sysctl (NULL, "hw.acpi.supported_sleep_state");
+ if (sleep_states != NULL) {
+ if (strstr (sleep_states, state) != NULL)
+ ret = TRUE;
+ }
+
+ g_free (sleep_states);
+
+ return ret;
+}
+
+/**
+ * dkp_backend_class_init:
+ * @klass: The DkpBackendClass
+ **/
+static void
+dkp_backend_class_init (DkpBackendClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = dkp_backend_finalize;
+
+ signals [SIGNAL_DEVICE_ADDED] =
+ g_signal_new ("device-added",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DkpBackendClass, device_added),
+ NULL, NULL, dkp_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+ signals [SIGNAL_DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DkpBackendClass, device_removed),
+ NULL, NULL, dkp_marshal_VOID__POINTER_POINTER,
+ G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+
+ g_type_class_add_private (klass, sizeof (DkpBackendPrivate));
+}
+
+/**
+ * dkp_backend_init:
+ **/
+static void
+dkp_backend_init (DkpBackend *backend)
+{
+ backend->priv = DKP_BACKEND_GET_PRIVATE (backend);
+ backend->priv->daemon = NULL;
+ backend->priv->device_list = NULL;
+ backend->priv->handle_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
+ backend->priv->poll_timer_id = 0;
+}
+
+/**
+ * dkp_backend_finalize:
+ **/
+static void
+dkp_backend_finalize (GObject *object)
+{
+ DkpBackend *backend;
+
+ g_return_if_fail (DKP_IS_BACKEND (object));
+
+ backend = DKP_BACKEND (object);
+
+ if (backend->priv->daemon != NULL)
+ g_object_unref (backend->priv->daemon);
+ if (backend->priv->device_list != NULL)
+ g_object_unref (backend->priv->device_list);
+ if (backend->priv->handle_map != NULL)
+ g_hash_table_unref (backend->priv->handle_map);
+ if (backend->priv->poll_timer_id > 0)
+ g_source_remove (backend->priv->poll_timer_id);
+
+ G_OBJECT_CLASS (dkp_backend_parent_class)->finalize (object);
+}
+
+/**
+ * dkp_backend_new:
+ *
+ * Return value: a new %DkpBackend object.
+ **/
+DkpBackend *
+dkp_backend_new (void)
+{
+ DkpBackend *backend;
+ backend = g_object_new (DKP_TYPE_BACKEND, NULL);
+ return DKP_BACKEND (backend);
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+dkp_backend_test (gpointer user_data)
+{
+ EggTest *test = (EggTest *) user_data;
+ DkpBackend *backend;
+
+ if (!egg_test_start (test, "DkpBackend"))
+ return;
+
+ /************************************************************/
+ egg_test_title (test, "get instance");
+ backend = dkp_backend_new ();
+ egg_test_assert (test, backend != NULL);
+
+ /* unref */
+ g_object_unref (backend);
+
+ egg_test_end (test);
+}
+#endif
+
diff --git a/src/freebsd/dkp-devd.c b/src/freebsd/dkp-devd.c
new file mode 100644
index 0000000..352a1b9
--- /dev/null
+++ b/src/freebsd/dkp-devd.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * dkp-devd.c : process devd events
+ *
+ * Copyright (C) 2006, 2007 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "config.h"
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "egg-debug.h"
+
+#include "dkp-backend.h"
+#include "dkp-backend-acpi.h"
+#include "dkp-devd.h"
+
+#define DKP_DEVD_SOCK_PATH "/var/run/devd.pipe"
+
+#define DKP_DEVD_EVENT_NOTIFY '!'
+#define DKP_DEVD_EVENT_ADD '+'
+#define DKP_DEVD_EVENT_REMOVE '-'
+#define DKP_DEVD_EVENT_NOMATCH '?'
+
+static DkpDevdHandler *handlers[] = {
+ &dkp_backend_acpi_devd_handler,
+};
+
+static gboolean dkp_devd_inited = FALSE;
+
+#if 0
+static GHashTable *
+dkp_devd_parse_params (const char *str)
+{
+ GHashTable *params;
+ char **pairs;
+ int i;
+
+ g_return_val_if_fail(str != NULL, FALSE);
+
+ params = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ pairs = g_strsplit(str, " ", 0);
+ for (i = 0; pairs[i]; i++) {
+ char *equal;
+
+ equal = strchr(pairs[i], '=');
+ g_hash_table_insert(params,
+ equal ? g_strndup(pairs[i], equal - pairs[i]) : g_strdup(pairs[i]),
+ equal ? g_strdup(equal + 1) : NULL);
+ }
+ g_strfreev(pairs);
+
+ return params;
+}
+#endif
+
+static gboolean
+dkp_devd_parse_notify (const char *event,
+ char **system,
+ char **subsystem,
+ char **type,
+ char **data)
+{
+ char **items;
+ gboolean status = FALSE;
+
+ /*
+ !system=IFNET subsystem=bge0 type=LINK_DOWN
+ */
+
+ g_return_val_if_fail(event != NULL, FALSE);
+ g_return_val_if_fail(system != NULL, FALSE);
+ g_return_val_if_fail(subsystem != NULL, FALSE);
+ g_return_val_if_fail(type != NULL, FALSE);
+ g_return_val_if_fail(data != NULL, FALSE);
+
+ items = g_strsplit(event, " ", 0);
+ if (g_strv_length(items) < 3)
+ goto end;
+
+ if (! g_str_has_prefix(items[0], "system=") ||
+ ! g_str_has_prefix(items[1], "subsystem=") ||
+ ! g_str_has_prefix(items[2], "type="))
+ goto end;
+
+ *system = g_strdup(items[0] + 7);
+ *subsystem = g_strdup(items[1] + 10);
+ *type = g_strdup(items[2] + 5);
+ *data = g_strdup(items[3]); /* may be NULL */
+
+ status = TRUE;
+
+end:
+ g_strfreev(items);
+ return status;
+}
+
+static void
+dkp_devd_process_notify_event (DkpBackend *backend,
+ const char *system,
+ const char *subsystem,
+ const char *type,
+ const char *data)
+{
+ int i;
+
+ g_return_if_fail(backend != NULL);
+ g_return_if_fail(system != NULL);
+ g_return_if_fail(subsystem != NULL);
+ g_return_if_fail(type != NULL);
+ g_return_if_fail(data != NULL);
+
+ for (i = 0; i < (int) G_N_ELEMENTS(handlers); i++)
+ if (handlers[i]->notify && handlers[i]->notify(backend, system, subsystem, type, data))
+ return;
+
+ /* no default action */
+}
+
+static void
+dkp_devd_process_event (const char *event, gpointer user_data)
+{
+ DkpBackend *backend;
+
+ g_return_if_fail(event != NULL);
+
+ backend = DKP_BACKEND(user_data);
+
+ egg_debug("received devd event: '%s'", event);
+
+ switch (event[0]) {
+ case DKP_DEVD_EVENT_ADD:
+ case DKP_DEVD_EVENT_REMOVE:
+ /* Do nothing as we don't currently hotplug ACPI devices. */
+ return;
+
+ case DKP_DEVD_EVENT_NOTIFY: {
+ char *system;
+ char *subsystem;
+ char *type;
+ char *data;
+
+ if (! dkp_devd_parse_notify(event + 1, &system, &subsystem, &type, &data))
+ goto malformed;
+
+ dkp_devd_process_notify_event(backend, system, subsystem, type, data);
+
+ g_free(system);
+ g_free(subsystem);
+ g_free(type);
+ g_free(data);
+ }
+ return;
+
+ case DKP_DEVD_EVENT_NOMATCH:
+ /* Do nothing. */
+ return;
+ }
+
+malformed:
+ egg_warning("malformed devd event: %s", event);
+}
+
+static gboolean
+dkp_devd_event_cb (GIOChannel *source, GIOCondition condition,
+ gpointer user_data)
+{
+ char *event;
+ gsize terminator;
+ GIOStatus status;
+
+ status = g_io_channel_read_line(source, &event, NULL, &terminator, NULL);
+
+ if (status == G_IO_STATUS_NORMAL) {
+ event[terminator] = 0;
+ dkp_devd_process_event(event, user_data);
+ g_free(event);
+ } else if (status == G_IO_STATUS_AGAIN) {
+ dkp_devd_init(DKP_BACKEND(user_data));
+ if (dkp_devd_inited) {
+ int fd;
+
+ fd = g_io_channel_unix_get_fd(source);
+ g_io_channel_shutdown(source, FALSE, NULL);
+ close(fd);
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void
+dkp_devd_init (DkpBackend *backend)
+{
+ int event_fd;
+ struct sockaddr_un addr;
+
+ event_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (event_fd < 0) {
+ egg_warning("failed to create event socket: '%s'", g_strerror(errno));
+ dkp_devd_inited = FALSE;
+ return;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, DKP_DEVD_SOCK_PATH, sizeof(addr.sun_path));
+ if (connect(event_fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+ GIOChannel *channel;
+
+ channel = g_io_channel_unix_new(event_fd);
+ g_io_add_watch(channel, G_IO_IN, dkp_devd_event_cb, backend);
+ g_io_channel_unref(channel);
+ dkp_devd_inited = TRUE;
+ } else {
+ egg_warning("failed to connect to %s: '%s'", DKP_DEVD_SOCK_PATH,
+ g_strerror(errno));
+ close(event_fd);
+ dkp_devd_inited = FALSE;
+ }
+}
diff --git a/src/freebsd/dkp-devd.h b/src/freebsd/dkp-devd.h
new file mode 100644
index 0000000..b5e86ee
--- /dev/null
+++ b/src/freebsd/dkp-devd.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * dkp-devd.h : process devd events
+ *
+ * Copyright (C) 2006, 2009 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef _DKP_DEVD_H
+#define _DKP_DEVD_H
+
+#include "config.h"
+
+#include "dkp-backend.h"
+
+#include <glib.h>
+
+typedef struct
+{
+ /* return TRUE to consume the event and stop processing */
+
+ gboolean (*notify) (DkpBackend *backend,
+ const char *system,
+ const char *subsystem,
+ const char *type,
+ const char *data); /* may be NULL */
+} DkpDevdHandler;
+
+void dkp_devd_init (DkpBackend *backend);
+
+#endif /* _DKP_DEVD_H */
diff --git a/src/freebsd/dkp-device-supply.c b/src/freebsd/dkp-device-supply.c
new file mode 100644
index 0000000..01f5be8
--- /dev/null
+++ b/src/freebsd/dkp-device-supply.c
@@ -0,0 +1,544 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "config.h"
+
+#include <string.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dev/acpica/acpiio.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gprintf.h>
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+
+#include "dkp-acpi-native.h"
+#include "dkp-util.h"
+
+#include "egg-debug.h"
+
+#include "dkp-enum.h"
+#include "dkp-device-supply.h"
+
+#define DKP_ACPIDEV "/dev/acpi"
+
+G_DEFINE_TYPE (DkpDeviceSupply, dkp_device_supply, DKP_TYPE_DEVICE)
+
+static gboolean dkp_device_supply_refresh (DkpDevice *device);
+static DkpDeviceTechnology dkp_device_supply_convert_device_technology (const char *type);
+static gboolean dkp_device_supply_acline_coldplug (DkpDevice *device);
+static gboolean dkp_device_supply_battery_coldplug (DkpDevice *device, DkpAcpiNative *native);
+static gboolean dkp_device_supply_acline_set_properties (DkpDevice *device);
+static gboolean dkp_device_supply_battery_set_properties (DkpDevice *device, DkpAcpiNative *native);
+static gboolean dkp_device_supply_get_on_battery (DkpDevice *device, gboolean *on_battery);
+static gboolean dkp_device_supply_get_low_battery (DkpDevice *device, gboolean *low_battery);
+static gboolean dkp_device_supply_get_online (DkpDevice *device, gboolean *online);
+
+/**
+ * dkp_device_supply_convert_device_technology:
+ *
+ * This is taken from linux/dkp-device-supply.c.
+ **/
+static DkpDeviceTechnology
+dkp_device_supply_convert_device_technology (const char *type)
+{
+ if (type == NULL)
+ return DKP_DEVICE_TECHNOLOGY_UNKNOWN;
+ if (g_ascii_strcasecmp (type, "li-ion") == 0 ||
+ g_ascii_strcasecmp (type, "lion") == 0)
+ return DKP_DEVICE_TECHNOLOGY_LITHIUM_ION;
+ if (g_ascii_strcasecmp (type, "pb") == 0 ||
+ g_ascii_strcasecmp (type, "pbac") == 0)
+ return DKP_DEVICE_TECHNOLOGY_LEAD_ACID;
+ if (g_ascii_strcasecmp (type, "lip") == 0 ||
+ g_ascii_strcasecmp (type, "lipo") == 0 ||
+ g_ascii_strcasecmp (type, "li-poly") == 0)
+ return DKP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER;
+ if (g_ascii_strcasecmp (type, "nimh") == 0)
+ return DKP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE;
+ if (g_ascii_strcasecmp (type, "lifo") == 0)
+ return DKP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE;
+ return DKP_DEVICE_TECHNOLOGY_UNKNOWN;
+}
+
+/**
+ * dkp_device_supply_reset_values:
+ **/
+static void
+dkp_device_supply_reset_values (DkpDevice *device)
+{
+ /* reset to default */
+ g_object_set (device,
+ "vendor", NULL,
+ "model", NULL,
+ "serial", NULL,
+ "update-time", (guint64) 0,
+ "power-supply", FALSE,
+ "online", FALSE,
+ "energy", (gdouble) 0.0,
+ "is-present", FALSE,
+ "is-rechargeable", FALSE,
+ "has-history", FALSE,
+ "has-statistics", FALSE,
+ "state", DKP_DEVICE_STATE_UNKNOWN,
+ "capacity", (gdouble) 0.0,
+ "energy-empty", (gdouble) 0.0,
+ "energy-full", (gdouble) 0.0,
+ "energy-full-design", (gdouble) 0.0,
+ "energy-rate", (gdouble) 0.0,
+ "voltage", (gdouble) 0.0,
+ "time-to-empty", (guint64) 0,
+ "time-to-full", (guint64) 0,
+ "percentage", (gdouble) 0.0,
+ "technology", DKP_DEVICE_TECHNOLOGY_UNKNOWN,
+ NULL);
+}
+
+/**
+ * dkp_device_supply_acline_coldplug:
+ **/
+static gboolean
+dkp_device_supply_acline_coldplug (DkpDevice *device)
+{
+ gboolean ret;
+
+ g_object_set (device,
+ "online", FALSE,
+ "power-supply", TRUE,
+ "type", DKP_DEVICE_TYPE_LINE_POWER,
+ NULL);
+
+ ret = dkp_device_supply_acline_set_properties (device);
+
+ return ret;
+}
+
+/**
+ * dkp_device_supply_battery_coldplug:
+ **/
+static gboolean
+dkp_device_supply_battery_coldplug (DkpDevice *device, DkpAcpiNative *native)
+{
+ gboolean ret;
+
+ g_object_set (device, "type", DKP_DEVICE_TYPE_BATTERY, NULL);
+ ret = dkp_device_supply_battery_set_properties (device, native);
+
+ return ret;
+}
+
+
+/**
+ * dkp_device_supply_battery_set_properties:
+ **/
+static gboolean
+dkp_device_supply_battery_set_properties (DkpDevice *device, DkpAcpiNative *native)
+{
+ int fd;
+ gdouble volt, dvolt, rate, lastfull, cap, dcap, lcap, capacity;
+ gboolean is_present;
+ gboolean ret = FALSE;
+ guint64 time_to_empty, time_to_full;
+ char *vendor, *model, *serial;
+ DkpDeviceTechnology technology;
+ DkpDeviceState state;
+ union acpi_battery_ioctl_arg battif, battst, battinfo;
+
+ if (!dkp_has_sysctl ("hw.acpi.battery.units"))
+ return FALSE;
+
+ battif.unit = battst.unit = battinfo.unit =
+ dkp_acpi_native_get_unit (native);
+ fd = open (DKP_ACPIDEV, O_RDONLY);
+ if (fd < 0) {
+ egg_warning ("unable to open %s: '%s'", DKP_ACPIDEV, g_strerror (errno));
+ return FALSE;
+ }
+
+ if (ioctl (fd, ACPIIO_BATT_GET_BIF, &battif) == -1) {
+ egg_warning ("ioctl ACPIIO_BATT_GET_BIF failed for battery %d: '%s'", battif.unit, g_strerror (errno));
+ goto end;
+ }
+
+ if (ioctl (fd, ACPIIO_BATT_GET_BST, &battst) == -1) {
+ egg_warning ("ioctl ACPIIO_BATT_GET_BST failed for battery %d: '%s'", battst.unit, g_strerror (errno));
+ goto end;
+ }
+
+ if (ioctl (fd, ACPIIO_BATT_GET_BATTINFO, &battinfo) == -1) {
+ egg_warning ("ioctl ACPIIO_BATT_GET_BATTINFO failed for battery %d: '%s'", battinfo.unit, g_strerror (errno));
+ goto end;
+ }
+
+ ret = TRUE;
+
+ is_present = (battst.bst.state == ACPI_BATT_STAT_NOT_PRESENT) ? FALSE : TRUE;
+ g_object_set (device, "is-present", is_present, NULL);
+
+ if (!is_present) {
+ dkp_device_supply_reset_values (device);
+ goto end;
+ }
+
+ vendor = dkp_make_safe_string (battif.bif.oeminfo);
+ model = dkp_make_safe_string (battif.bif.model);
+ serial = dkp_make_safe_string (battif.bif.serial);
+ technology = dkp_device_supply_convert_device_technology (battif.bif.type);
+
+ g_object_set (device,
+ "vendor", vendor,
+ "model", model,
+ "serial", serial,
+ "power-supply", TRUE,
+ "technology", technology,
+ "has-history", TRUE,
+ "has-statistics", TRUE,
+ NULL);
+ g_free (vendor);
+ g_free (model);
+ g_free (serial);
+
+ g_object_set (device, "is-rechargeable",
+ battif.bif.btech == 0 ? FALSE : TRUE, NULL);
+
+ volt = (gdouble) battst.bst.volt;
+ dvolt = (gdouble) battif.bif.dvol;
+ lastfull = (gdouble) battif.bif.lfcap;
+ dcap = (gdouble) battif.bif.dcap;
+ rate = (gdouble) battst.bst.rate;
+ cap = (gdouble) battst.bst.cap;
+ lcap = (gdouble) battif.bif.lcap;
+ if (rate == 0xffff)
+ rate = 0.0f;
+ if (rate > 100.0f * 1000.0f)
+ rate = 0.0f;
+
+ dvolt /= 1000.0f;
+ volt /= 1000.0f;
+
+ if (battif.bif.units == ACPI_BIF_UNITS_MA) {
+ if (dvolt <= 0.0f)
+ dvolt = 1.0f;
+ if (volt <= 0.0f || volt > dvolt)
+ volt = dvolt;
+
+ dcap *= volt;
+ lastfull *= volt;
+ rate *= volt;
+ cap *= volt;
+ lcap *= volt;
+ }
+
+ dcap /= 1000.0f;
+ lastfull /= 1000.0f;
+ rate /= 1000.0f;
+ cap /= 1000.0f;
+ lcap /= 1000.0f;
+
+ if (cap == 0.0f)
+ rate = 0.0f;
+
+ capacity = 0.0f;
+ if (lastfull > 0 && dcap > 0) {
+ capacity = (lastfull / dcap) * 100.0f;
+ if (capacity < 0)
+ capacity = 0.0f;
+ if (capacity > 100.0)
+ capacity = 100.0f;
+ }
+
+ g_object_set (device,
+ "percentage", (gdouble) battinfo.battinfo.cap,
+ "energy", cap,
+ "energy-full", lastfull,
+ "energy-full-design", dcap,
+ "energy-rate", rate,
+ "energy-empty", lcap,
+ "voltage", volt,
+ "capacity", capacity,
+ NULL);
+
+ time_to_empty = 0;
+ time_to_full = 0;
+
+ if (battinfo.battinfo.state & ACPI_BATT_STAT_DISCHARG) {
+ state = DKP_DEVICE_STATE_DISCHARGING;
+ if (battinfo.battinfo.min > 0)
+ time_to_empty = battinfo.battinfo.min * 60;
+ else if (rate > 0) {
+ time_to_empty = 3600 * (cap / rate);
+ if (time_to_empty > (20 * 60 * 60))
+ time_to_empty = 0;
+ }
+ } else if (battinfo.battinfo.state & ACPI_BATT_STAT_CHARGING) {
+ state = DKP_DEVICE_STATE_CHARGING;
+ if (battinfo.battinfo.min > 0)
+ time_to_full = battinfo.battinfo.min * 60;
+ else if (rate > 0) {
+ time_to_full = 3600 * ((lastfull - cap) / rate);
+ if (time_to_full > (20 * 60 * 60))
+ time_to_full = 0;
+ }
+ } else if (battinfo.battinfo.state & ACPI_BATT_STAT_CRITICAL) {
+ state = DKP_DEVICE_STATE_EMPTY;
+ } else if (battinfo.battinfo.state == 0) {
+ state = DKP_DEVICE_STATE_FULLY_CHARGED;
+ } else {
+ state = DKP_DEVICE_STATE_UNKNOWN;
+ }
+
+ g_object_set (device,
+ "state", state,
+ "time-to-empty", time_to_empty,
+ "time-to-full", time_to_full,
+ NULL);
+
+end:
+ close (fd);
+ return ret;
+}
+
+/**
+ * dkp_device_supply_acline_set_properties:
+ **/
+static gboolean
+dkp_device_supply_acline_set_properties (DkpDevice *device)
+{
+ int acstate;
+
+ if (dkp_get_int_sysctl (&acstate, NULL, "hw.acpi.acline")) {
+ g_object_set (device, "online", acstate ? TRUE : FALSE, NULL);
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
+
+/**
+ * dkp_device_supply_coldplug:
+ * Return %TRUE on success, %FALSE if we failed to get data and should be removed
+ **/
+static gboolean
+dkp_device_supply_coldplug (DkpDevice *device)
+{
+ DkpAcpiNative *native;
+ const gchar *native_path;
+ const gchar *driver;
+ gboolean ret = FALSE;
+
+ dkp_device_supply_reset_values (device);
+
+ native = DKP_ACPI_NATIVE (dkp_device_get_native (device));
+ native_path = dkp_acpi_native_get_path (native);
+ driver = dkp_acpi_native_get_driver (native);
+ if (native_path == NULL) {
+ egg_warning ("could not get native path for %p", device);
+ goto out;
+ }
+
+ if (!strcmp (native_path, "hw.acpi.acline")) {
+ ret = dkp_device_supply_acline_coldplug (device);
+ goto out;
+ }
+
+ if (!g_strcmp0 (driver, "battery")) {
+ ret = dkp_device_supply_battery_coldplug (device, native);
+ goto out;
+ }
+
+ egg_warning ("invalid device %s with driver %s", native_path, driver);
+
+out:
+ return ret;
+}
+
+/**
+ * dkp_device_supply_refresh:
+ *
+ * Return %TRUE on success, %FALSE if we failed to refresh or no data
+ **/
+static gboolean
+dkp_device_supply_refresh (DkpDevice *device)
+{
+ GObject *object;
+ GTimeVal timeval;
+ DkpDeviceType type;
+ gboolean ret;
+
+ g_object_get (device, "type", &type, NULL);
+ switch (type) {
+ case DKP_DEVICE_TYPE_LINE_POWER:
+ ret = dkp_device_supply_acline_set_properties (device);
+ break;
+ case DKP_DEVICE_TYPE_BATTERY:
+ object = dkp_device_get_native (device);
+ ret = dkp_device_supply_battery_set_properties (device, DKP_ACPI_NATIVE (object));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (ret) {
+ g_get_current_time (&timeval);
+ g_object_set (device, "update-time", (guint64) timeval.tv_sec, NULL);
+ }
+
+ return ret;
+}
+
+/**
+ * dkp_device_supply_get_on_battery:
+ **/
+static gboolean
+dkp_device_supply_get_on_battery (DkpDevice *device, gboolean *on_battery)
+{
+ DkpDeviceType type;
+ DkpDeviceState state;
+ gboolean is_present;
+
+ g_return_val_if_fail (on_battery != NULL, FALSE);
+
+ g_object_get (device,
+ "type", &type,
+ "state", &state,
+ "is-present", &is_present,
+ NULL);
+
+ if (type != DKP_DEVICE_TYPE_BATTERY)
+ return FALSE;
+ if (state == DKP_DEVICE_STATE_UNKNOWN)
+ return FALSE;
+ if (!is_present)
+ return FALSE;
+
+ *on_battery = (state == DKP_DEVICE_STATE_DISCHARGING);
+ return TRUE;
+}
+
+/**
+ * dkp_device_supply_get_low_battery:
+ **/
+static gboolean
+dkp_device_supply_get_low_battery (DkpDevice *device, gboolean *low_battery)
+{
+ gboolean ret;
+ gboolean on_battery;
+ gdouble percentage;
+
+ g_return_val_if_fail (low_battery != NULL, FALSE);
+
+ ret = dkp_device_supply_get_on_battery (device, &on_battery);
+ if (!ret)
+ return FALSE;
+
+ if (!on_battery) {
+ *low_battery = FALSE;
+ return TRUE;
+ }
+
+ g_object_get (device, "percentage", &percentage, NULL);
+ *low_battery = (percentage < 10.0f);
+ return TRUE;
+}
+
+/**
+ * dkp_device_supply_get_online:
+ **/
+static gboolean
+dkp_device_supply_get_online (DkpDevice *device, gboolean *online)
+{
+ DkpDeviceType type;
+ gboolean online_tmp;
+
+ g_return_val_if_fail (online != NULL, FALSE);
+
+ g_object_get (device,
+ "type", &type,
+ "online", &online_tmp,
+ NULL);
+
+ if (type != DKP_DEVICE_TYPE_LINE_POWER)
+ return FALSE;
+
+ *online = online_tmp;
+
+ return TRUE;
+}
+
+/**
+ * dkp_device_supply_init:
+ **/
+static void
+dkp_device_supply_init (DkpDeviceSupply *supply)
+{
+}
+
+/**
+ * dkp_device_supply_finalize:
+ **/
+static void
+dkp_device_supply_finalize (GObject *object)
+{
+ DkpDeviceSupply *supply;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (DKP_IS_SUPPLY (object));
+
+ supply = DKP_DEVICE_SUPPLY (object);
+
+ G_OBJECT_CLASS (dkp_device_supply_parent_class)->finalize (object);
+}
+
+/**
+ * dkp_device_supply_class_init:
+ **/
+static void
+dkp_device_supply_class_init (DkpDeviceSupplyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ DkpDeviceClass *device_class = DKP_DEVICE_CLASS (klass);
+
+ object_class->finalize = dkp_device_supply_finalize;
+ device_class->get_on_battery = dkp_device_supply_get_on_battery;
+ device_class->get_low_battery = dkp_device_supply_get_low_battery;
+ device_class->get_online = dkp_device_supply_get_online;
+ device_class->coldplug = dkp_device_supply_coldplug;
+ device_class->refresh = dkp_device_supply_refresh;
+}
+
+/**
+ * dkp_device_supply_new:
+ **/
+DkpDeviceSupply *
+dkp_device_supply_new (void)
+{
+ return g_object_new (DKP_TYPE_SUPPLY, NULL);
+}
+
diff --git a/src/freebsd/dkp-device-supply.h b/src/freebsd/dkp-device-supply.h
new file mode 100644
index 0000000..b767eac
--- /dev/null
+++ b/src/freebsd/dkp-device-supply.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+
+#ifndef __DKP_DEVICE_SUPPLY_H__
+#define __DKP_DEVICE_SUPPLY_H__
+
+#include <glib-object.h>
+#include "dkp-device.h"
+
+G_BEGIN_DECLS
+
+#define DKP_TYPE_SUPPLY (dkp_device_supply_get_type ())
+#define DKP_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DKP_TYPE_SUPPLY, DkpDeviceSupply))
+#define DKP_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DKP_TYPE_SUPPLY, DkpDeviceSupplyClass))
+#define DKP_IS_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DKP_TYPE_SUPPLY))
+#define DKP_IS_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DKP_TYPE_SUPPLY))
+#define DKP_DEVICE_SUPPLY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DKP_TYPE_SUPPLY, DkpDeviceSupplyClass))
+
+typedef struct DkpDeviceSupplyPrivate DkpDeviceSupplyPrivate;
+
+typedef struct
+{
+ DkpDevice parent;
+ DkpDeviceSupplyPrivate *priv;
+} DkpDeviceSupply;
+
+typedef struct
+{
+ DkpDeviceClass parent_class;
+} DkpDeviceSupplyClass;
+
+GType dkp_device_supply_get_type (void);
+DkpDeviceSupply *dkp_device_supply_new (void);
+
+G_END_DECLS
+
+#endif /* __DKP_DEVICE_SUPPLY_H__ */
+
diff --git a/src/freebsd/dkp-native.c b/src/freebsd/dkp-native.c
new file mode 100644
index 0000000..944111a
--- /dev/null
+++ b/src/freebsd/dkp-native.c
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <glib.h>
+#include "dkp-acpi-native.h"
+
+#include "dkp-native.h"
+
+/**
+ * dkp_native_get_native_path:
+ * @object: the native tracking object
+ *
+ * This converts a GObject used as the device data into a native path.
+ *
+ * Return value: The native path for the device which is unique, e.g. "/sys/class/power/BAT1"
+ **/
+const gchar *
+dkp_native_get_native_path (GObject *object)
+{
+ return dkp_acpi_native_get_path (DKP_ACPI_NATIVE (object));
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef EGG_TEST
+#include "egg-test.h"
+
+void
+dkp_native_test (gpointer user_data)
+{
+ EggTest *test = (EggTest *) user_data;
+ DkpAcpiNative *dan;
+ const gchar *path;
+
+ if (!egg_test_start (test, "DkpNative"))
+ return;
+
+ /************************************************************/
+ egg_test_title (test, "get instance");
+ dan = dkp_acpi_native_new_driver_unit ("battery", 0);
+ path = dkp_native_get_native_path (dan);
+ egg_test_assert (test, (g_strcmp0 (path, "dev.battery.0") == 0));
+ g_object_unref (dan);
+
+ egg_test_end (test);
+}
+#endif
+
diff --git a/src/freebsd/dkp-util.c b/src/freebsd/dkp-util.c
new file mode 100644
index 0000000..104eb0b
--- /dev/null
+++ b/src/freebsd/dkp-util.c
@@ -0,0 +1,145 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * dkp-util.c : utilities
+ *
+ * Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <glib.h>
+
+#include "egg-debug.h"
+
+#include "dkp-util.h"
+
+gboolean
+dkp_has_sysctl (const char *format, ...)
+{
+ va_list args;
+ char *name;
+ size_t value_len;
+ gboolean status;
+
+ g_return_val_if_fail(format != NULL, FALSE);
+
+ va_start(args, format);
+ name = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ status = sysctlbyname(name, NULL, &value_len, NULL, 0) == 0;
+
+ g_free(name);
+ return status;
+}
+
+gboolean
+dkp_get_int_sysctl (int *value, GError **err, const char *format, ...)
+{
+ va_list args;
+ char *name;
+ size_t value_len = sizeof(int);
+ gboolean status;
+
+ g_return_val_if_fail(value != NULL, FALSE);
+ g_return_val_if_fail(format != NULL, FALSE);
+
+ va_start(args, format);
+ name = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ status = sysctlbyname(name, value, &value_len, NULL, 0) == 0;
+ if (! status)
+ g_set_error(err, 0, 0, "%s", g_strerror(errno));
+
+ g_free(name);
+ return status;
+}
+
+char *
+dkp_get_string_sysctl (GError **err, const char *format, ...)
+{
+ va_list args;
+ char *name;
+ size_t value_len;
+ char *str = NULL;
+
+ g_return_val_if_fail(format != NULL, FALSE);
+
+ va_start(args, format);
+ name = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ if (sysctlbyname(name, NULL, &value_len, NULL, 0) == 0) {
+ str = g_new(char, value_len + 1);
+ if (sysctlbyname(name, str, &value_len, NULL, 0) == 0)
+ str[value_len] = 0;
+ else {
+ g_free(str);
+ str = NULL;
+ }
+ }
+
+ if (! str)
+ g_set_error(err, 0, 0, "%s", g_strerror(errno));
+
+ g_free(name);
+ return str;
+}
+
+/**
+ * dkp_util_make_safe_string:
+ *
+ * This is adapted from linux/dkp-device-supply.c.
+ **/
+char *
+dkp_make_safe_string (const char *text)
+{
+ guint i;
+ guint idx = 0;
+ char *ret;
+
+ /* no point in checking */
+ if (text == NULL)
+ return NULL;
+
+ ret = g_strdup (text);
+
+ /* shunt up only safe chars */
+ for (i = 0; ret[i] != '\0'; i++) {
+ if (g_ascii_isprint (ret[i])) {
+ /* only copy if the address is going to change */
+ if (idx != i)
+ ret[idx] = ret[i];
+ idx++;
+ } else {
+ egg_debug ("invalid char '%c'", ret[i]);
+ }
+ }
+
+ /* ensure null terminated */
+ ret[idx] = '\0';
+
+ return ret;
+}
diff --git a/src/freebsd/dkp-util.h b/src/freebsd/dkp-util.h
new file mode 100644
index 0000000..ff4fe24
--- /dev/null
+++ b/src/freebsd/dkp-util.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * dkp-util.h : utilities
+ *
+ * Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@FreeBSD.org>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef _DKP_UTIL_H
+#define _DKP_UTIL_H
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <glib.h>
+
+#define DKP_BOOL_TO_STRING(val) ((val) ? "true" : "false")
+
+#define DKP_LIST_FOREACH(var, head) \
+ for ((var) = (head); \
+ (var); \
+ (var) = (var)->next)
+
+gboolean dkp_has_sysctl (const char *format, ...) G_GNUC_PRINTF(1, 2);
+gboolean dkp_get_int_sysctl (int *value,
+ GError **err,
+ const char *format,
+ ...) G_GNUC_PRINTF(3, 4);
+char *dkp_get_string_sysctl (GError **err,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+
+char *dkp_make_safe_string (const char *text);
+
+#endif /* _DKP_UTIL_H */