diff -ur upower-0.99.4-orig/configure.ac upower-0.99.4/configure.ac
--- upower-0.99.4-orig/configure.ac	2017-12-22 13:49:01.103499900 +0000
+++ upower-0.99.4/configure.ac	2017-12-22 13:52:02.433807222 +0000
@@ -182,13 +182,14 @@
 dnl ---------------------------------------------------------------------------
 AC_ARG_WITH([backend],
 	    AS_HELP_STRING([--with-backend=<option>],
-			   [Default backend to use linux, freebsd, openbsd, dummy (dummy)]))
+			   [Default backend to use linux, freebsd, openbsd, illumos, dummy (dummy)]))
 # default to a sane option
 AC_CANONICAL_HOST
 if test x$with_backend = x; then
 	AS_CASE([$host],
 		[*-linux*],   [with_backend=linux],
 		[*-*freebsd*], [with_backend=freebsd],
+		[*-*solaris*], [with_backend=illumos],
 		[*-openbsd*], [with_backend=openbsd],
 		              [with_backend=dummy])
 fi
@@ -216,6 +217,7 @@
 AM_CONDITIONAL(BACKEND_TYPE_LINUX, [test x$with_backend = xlinux])
 AM_CONDITIONAL(BACKEND_TYPE_FREEBSD, [test x$with_backend = xfreebsd])
 AM_CONDITIONAL(BACKEND_TYPE_OPENBSD, [test x$with_backend = xopenbsd])
+AM_CONDITIONAL(BACKEND_TYPE_ILLUMOS, [test x$with_backend = xillumos])
 
 dnl ---------------------------------------------------------------------------
 dnl - Build self tests
@@ -252,6 +254,7 @@
 src/dummy/Makefile
 src/freebsd/Makefile
 src/openbsd/Makefile
+src/illumos/Makefile
 src/linux/Makefile
 src/bsd/Makefile
 tools/Makefile
--- upower-0.99.4-orig/src/Makefile.am	2017-12-22 13:49:01.088869218 +0000
+++ upower-0.99.4/src/Makefile.am	2017-12-22 14:11:15.858740851 +0000
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
-DIST_SUBDIRS = dummy freebsd linux openbsd bsd
-SUBDIRS = dummy freebsd linux openbsd
+DIST_SUBDIRS = dummy freebsd linux openbsd bsd illumos
+SUBDIRS = dummy freebsd linux openbsd illumos
 
 if BACKEND_TYPE_FREEBSD
 SUBDIRS += bsd
@@ -11,6 +11,10 @@
 SUBDIRS += bsd
 endif
 
+if BACKEND_TYPE_ILLUMOS
+SUBDIRS += bsd
+endif
+
 AM_CPPFLAGS = \
 	$(PIE_CFLAGS)						\
 	-I$(top_builddir)/src -I$(top_srcdir)/src		\
@@ -90,6 +94,13 @@
 	bsd/libupsharedcommon.la
 endif
 
+if BACKEND_TYPE_ILLUMOS
+upowerd_LDADD +=						\
+	illumos/libupshared.la				\
+	bsd/libupsharedcommon.la
+endif
+
+
 if BACKEND_TYPE_LINUX
 upowerd_LDADD += 						\
 	linux/libupshared.la					\
diff -urN upower-0.99.4-orig/src/illumos/Makefile.am upower-0.99.4/src/illumos/Makefile.am
--- upower-0.99.4/src/illumos/Makefile.am.~1~	2017-12-28 12:33:16.160144165 +0000
+++ upower-0.99.4/src/illumos/Makefile.am	2017-12-28 12:37:16.557439612 +0000
@@ -0,0 +1,31 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CPPFLAGS = \
+	-I$(top_builddir)/src -I$(top_srcdir)/src		\
+	-I$(top_builddir)/ -I$(top_srcdir)/			\
+	-DUP_COMPILATION					\
+	-DG_LOG_DOMAIN=\"UPower-illumos\"			\
+	-I$(top_srcdir)/libupower-glib				\
+	$(POLKIT_CFLAGS)					\
+	$(GLIB_CFLAGS)
+
+if BACKEND_TYPE_ILLUMOS
+noinst_LTLIBRARIES = libupshared.la
+endif
+
+libupshared_la_SOURCES =					\
+	up-native.c						\
+	up-backend.c						\
+	$(BUILT_SOURCES)
+
+libupshared_la_CFLAGS =					\
+	$(WARNINGFLAGS_C)
+
+libupshared_la_LDFLAGS =					\
+	-lsysevent						\
+	-ldevinfo
+
+clean-local :
+	rm -f *~
+
+-include $(top_srcdir)/git.mk
diff -urN upower-0.99.4-orig/src/illumos/up-acpi-native.h upower-0.99.4/src/illumos/up-acpi-native.h
--- upower-0.99.4-orig/src/illumos/up-acpi-native.h	1970-01-01 03:00:00.000000000 +0000
+++ upower-0.99.4/src/illumos/up-acpi-native.h	2017-12-26 13:41:47.340610361 +0000
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Landry Breuil <landry@openbsd.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __UP_ACPI_NATIVE_H__
+#define __UP_ACPI_NATIVE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UP_TYPE_ACPI_NATIVE		(up_acpi_native_get_type ())
+#define UP_ACPI_NATIVE(o)	   	(G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_ACPI_NATIVE, UpAcpiNative))
+#define UP_ACPI_NATIVE_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_ACPI_NATIVE, UpAcpiNativeClass))
+#define UP_IS_ACPI_NATIVE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_ACPI_NATIVE))
+#define UP_IS_ACPI_NATIVE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_ACPI_NATIVE))
+#define UP_ACPI_NATIVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_ACPI_NATIVE, UpAcpiNativeClass))
+
+typedef struct
+{
+	GObject	parent;
+	gchar*	path;
+} UpAcpiNative;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} UpAcpiNativeClass;
+
+
+UpAcpiNative* up_acpi_native_new (const char*);
+const gchar * up_acpi_native_get_path (UpAcpiNative*);
+GType up_acpi_native_get_type (void);
+G_END_DECLS
+
+#endif
diff -urN upower-0.99.4-orig/src/illumos/up-backend.c upower-0.99.4/src/illumos/up-backend.c
--- upower-0.99.4/src/illumos/up-backend.c.~1~	2018-01-20 09:48:32.501653060 +0000
+++ upower-0.99.4/src/illumos/up-backend.c	2018-01-20 12:33:59.490627981 +0000
@@ -0,0 +1,918 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Landry Breuil <landry@openbsd.org>
+ * Copyright (C) 2018 Alexander Pyhalov <apyhalov@gmail.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "up-backend.h"
+#include "up-daemon.h"
+#include "up-device.h"
+#include "up-acpi-native.h"
+#include "up-backend-bsd-private.h"
+#include <stdio.h>
+#include <string.h> /* strcmp() */
+#include <libdevinfo.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/acpi_drv.h>
+#include <libsysevent.h>
+#include <sys/sysevent/dev.h>
+#include <sys/sysevent/pwrctl.h>
+
+#define DEVFS_PREFIX "/devices"
+
+#define BST_FLAG_DISCHARGING	(0x1)
+#define BST_FLAG_CHARGING	(0x2)
+
+#define DEVPATH_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789/_"
+
+#define POLL_INTERVAL	20*1000 /* 20 seconds */
+
+static void	up_backend_class_init	(UpBackendClass	*klass);
+static void	up_backend_init	(UpBackend		*backend);
+static void	up_backend_finalize	(GObject		*object);
+
+static int	up_backend_acpi_get_ac_online();
+static void	up_backend_update_lid_status(UpDaemon*);
+
+static gboolean		up_acpi_device_get_on_battery	(UpDevice *device, gboolean *on_battery);
+static gboolean		up_acpi_device_get_online		(UpDevice *device, gboolean *online);
+static gboolean		up_acpi_device_refresh		(UpDevice *device);
+
+static int		minor_device_ioctl(di_node_t node, void *arg);
+static int		estimate_time(int charge_rate, int current_charge, int last_fullcharge, int is_discharging, int is_charging);
+
+static char*		up_backend_get_ac_device_path(enum acpi_drv_type device);
+
+static sysevent_handle_t *shp;
+static void		up_backend_sysevent_dev_handler(sysevent_t *ev);
+static gboolean		sysevent_iochannel_data(GIOChannel *, GIOCondition, gpointer);
+static void		up_backend_initialize_sysevent_handler(UpBackend *backend);
+static int		sysevent_pipe_fds[2];
+static GIOChannel	*sysevent_iochannel;
+static gboolean		simulate_iochannel_data (gpointer data);
+
+#define UP_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_BACKEND, UpBackendPrivate))
+
+struct UpBackendPrivate
+{
+	UpDaemon		*daemon;
+	UpDevice		*ac;
+	UpDevice		*battery;
+	gboolean		has_ac_device; /* ac device node is present */
+	gboolean		has_bat_device; /* battery device node is present */
+	UpConfig		*config;
+	GDBusProxy		*seat_manager_proxy;
+};
+
+struct mdi_arg {
+	const char	*name;
+	gboolean	exact_match;
+	int		ctl;
+	gboolean	present;
+	gboolean	success;
+	void 		*result;
+	char		*device_path;
+};
+
+enum {
+	SIGNAL_DEVICE_ADDED,
+	SIGNAL_DEVICE_REMOVED,
+	SIGNAL_LAST
+};
+
+struct lid_state {
+	gboolean present;
+	gboolean open;
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE (UpBackend, up_backend, G_TYPE_OBJECT)
+
+/**
+ * functions called by upower daemon
+ **/
+
+
+/* those three ripped from freebsd/up-device-supply.c */
+gboolean
+up_acpi_device_get_on_battery (UpDevice *device, gboolean * on_battery)
+{
+	UpDeviceKind type;
+	UpDeviceState 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,
+		      (void*) NULL);
+
+	if (type != UP_DEVICE_KIND_BATTERY)
+		return FALSE;
+	if (state == UP_DEVICE_STATE_UNKNOWN)
+		return FALSE;
+	if (!is_present)
+		return FALSE;
+
+	*on_battery = (state == UP_DEVICE_STATE_DISCHARGING);
+	return TRUE;
+}
+
+gboolean
+up_acpi_device_get_online (UpDevice *device, gboolean * online)
+{
+	UpDeviceKind type;
+	gboolean online_tmp;
+
+	g_return_val_if_fail (online != NULL, FALSE);
+
+	g_object_get (device,
+		      "type", &type,
+		      "online", &online_tmp,
+		      (void*) NULL);
+
+	if (type != UP_DEVICE_KIND_LINE_POWER)
+		return FALSE;
+
+	*online = online_tmp;
+
+	return TRUE;
+}
+/**
+ * up_backend_coldplug:
+ * @backend: The %UpBackend class instance
+ * @daemon: The %UpDaemon controlling instance
+ *
+ * Finds all the devices already plugged in, and emits device-add signals for
+ * each of them.
+ *
+ * Return value: %TRUE for success
+ **/
+gboolean
+up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
+{
+	UpAcpiNative *acnative = NULL;
+	UpAcpiNative *battnative = NULL;
+	char *devpath;
+
+	backend->priv->daemon = g_object_ref (daemon);
+
+	if (backend->priv->has_ac_device || backend->priv->has_bat_device) {
+		up_backend_update_lid_status(daemon);
+	}
+
+	if (backend->priv->has_ac_device) {
+		devpath = up_backend_get_ac_device_path(ACPI_DRV_TYPE_AC);
+		if (devpath) {
+			devpath = g_strcanon(devpath, DEVPATH_ALLOWED_CHARS, '_');
+			acnative = up_acpi_native_new(devpath);
+			if (!up_device_coldplug (backend->priv->ac, backend->priv->daemon, G_OBJECT(acnative)))
+				g_warning ("failed to coldplug ac");
+			else
+				g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, acnative, backend->priv->ac);
+			g_free(devpath);
+		}
+	}
+
+	if (backend->priv->has_bat_device) {
+		devpath = up_backend_get_ac_device_path(ACPI_DRV_TYPE_CBAT);
+		if (devpath) {
+			devpath = g_strcanon(devpath, DEVPATH_ALLOWED_CHARS, '_');
+			battnative = up_acpi_native_new(devpath);
+			if (!up_device_coldplug (backend->priv->battery, backend->priv->daemon, G_OBJECT(battnative)))
+				g_warning ("failed to coldplug battery");
+			else
+				g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, battnative, backend->priv->battery);
+			g_free(devpath);
+		}
+	}
+
+	return TRUE;
+}
+
+/**
+ * up_backend_unplug:
+ * @backend: The %UpBackend class instance
+ *
+ * Forget about all learned devices, effectively undoing up_backend_coldplug.
+ * Resources are released without emitting signals.
+ */
+void
+up_backend_unplug (UpBackend *backend)
+{
+	if (backend->priv->daemon != NULL) {
+		g_object_unref (backend->priv->daemon);
+		backend->priv->daemon = NULL;
+	}
+}
+
+/**
+ * up_backend_get_seat_manager_proxy:
+ * @backend: The %UpBackend class instance
+ *
+ * Returns the seat manager object or NULL on error. [transfer none]
+ */
+GDBusProxy *
+up_backend_get_seat_manager_proxy (UpBackend  *backend)
+{
+	g_return_val_if_fail (UP_IS_BACKEND (backend), NULL);
+
+	return backend->priv->seat_manager_proxy;
+}
+
+/**
+ * up_backend_get_config:
+ * @backend: The %UpBackend class instance
+ *
+ * Returns the UpConfig object or NULL on error. [transfer none]
+ */
+UpConfig *
+up_backend_get_config (UpBackend  *backend)
+{
+	g_return_val_if_fail (UP_IS_BACKEND (backend), NULL);
+
+	return backend->priv->config;
+}
+
+
+/**
+ * illumos specific code
+ **/
+
+static gboolean
+up_backend_update_ac_state(UpDevice* device)
+{
+	gboolean new_is_online, cur_is_online;
+	int ret;
+
+	up_backend_update_lid_status(up_device_get_daemon(device));
+	ret = up_backend_acpi_get_ac_online();
+	if (ret < 0)
+		return FALSE;
+
+	g_object_get (device, "online", &cur_is_online, (void*) NULL);
+
+	new_is_online = (ret > 0 ? TRUE : FALSE);
+	if (cur_is_online != new_is_online)
+	{
+		g_object_set (device,
+			"online", new_is_online,
+			(void*) NULL);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+up_backend_update_battery_state(UpDevice* device)
+{
+	gdouble percentage = 0, new_percentage = 0;
+	gboolean is_present;
+	UpDeviceState cur_state, new_state;
+	gint64 cur_time_to_empty, new_time_to_empty; /* in seconds */
+
+	di_node_t root_node;
+	struct mdi_arg ma;
+	acpi_bst_t bst;
+	acpi_bif_t bif;
+	
+	new_state = UP_DEVICE_STATE_UNKNOWN;
+
+	memset(&bif, 0, sizeof(bif));
+	ma.name = "battery";
+	ma.exact_match = FALSE;
+	ma.ctl = ACPI_DRV_IOC_INFO;
+	ma.result = &bif;
+	
+     	errno = 0;
+     	if((root_node = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) {
+     	      g_error("di_init() failed: %s", g_strerror(errno));
+     	}
+     	di_walk_node(root_node, DI_WALK_CLDFIRST, &ma, minor_device_ioctl);
+	di_fini(root_node);
+	if (ma.device_path)
+		g_free(ma.device_path);
+	
+	if (!ma.success) {
+		/* If device file is present, but ioctl has failed, 
+		     consider that battery is absent */
+		if (ma.present) {
+			g_object_set (device,
+				"state", UP_DEVICE_STATE_EMPTY,
+				"percentage", (gdouble) 0.0,
+				"time-to-empty", (guint64) 0,
+				"is-present", FALSE,
+				(void*) NULL);
+			/* Reset some known fields which remain untouched below. */
+			g_object_set(device,
+				"is-rechargeable", FALSE,
+				"energy", (gdouble) 0.0,
+				"energy-empty", (gdouble) 0.0,
+				"energy-full", (gdouble) 0.0,
+				"energy-full-design", (gdouble) 0.0,
+				"energy-rate", (gdouble) 0.0,
+				NULL);
+			return TRUE;
+		} else {
+			g_warning("Couldn't get state of battery");
+			return FALSE;
+		}
+	}
+
+
+	memset(&bst, 0, sizeof(bst));
+	ma.name = "battery";
+	ma.exact_match = FALSE;
+	ma.ctl = ACPI_DRV_IOC_STATUS;
+	ma.result = &bst;
+
+     	errno = 0;
+     	if((root_node = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) {
+     	      g_error("di_init() failed: %s", g_strerror(errno));
+              return FALSE;
+     	}
+     	di_walk_node(root_node, DI_WALK_CLDFIRST, &ma, minor_device_ioctl);
+	di_fini(root_node);
+	if (ma.device_path)
+		g_free(ma.device_path);
+
+	g_object_get (device,
+		"state", &cur_state,
+		"percentage", &percentage,
+		"time-to-empty", &cur_time_to_empty,
+		"is-present", &is_present,
+		(void*) NULL);
+
+	if (ma.success) {
+	        int reporting_rate;
+		int reporting_current;
+		int reporting_lastfull;
+		int reporting_lowcap;
+		int reporting_design_capacity;
+		int design_voltage;
+		int present_voltage;
+		int charging, discharging;
+		
+		charging = bst.bst_state & BST_FLAG_CHARGING;
+		discharging = bst.bst_state & BST_FLAG_DISCHARGING;
+
+		reporting_rate = bst.bst_rate;
+		reporting_current = bst.bst_rem_cap;
+		reporting_lastfull = bif.bif_last_cap;
+		reporting_lowcap = bif.bif_low_cap;
+		design_voltage = bif.bif_voltage;
+		present_voltage = bst.bst_voltage;
+		reporting_design_capacity = bif.bif_design_cap;
+		if (bif.bif_unit) {	/* Battery is reporting in mAh */
+				/*
+		                 * If the present_voltage is inaccurate, set it to the
+               			 * design_voltage.
+                 		 */
+				if (((present_voltage * 10) < design_voltage) ||
+				    (present_voltage <= 0) ||
+				    (present_voltage > design_voltage)) {
+				        present_voltage = design_voltage;
+				}
+				reporting_rate = (reporting_rate * present_voltage) / 1000;
+				reporting_lastfull = (reporting_lastfull * present_voltage) /1000;
+				reporting_current = (reporting_current * present_voltage) / 1000;
+				reporting_design_capacity = (reporting_design_capacity * present_voltage) / 1000;
+				reporting_lowcap = (reporting_lowcap * present_voltage) / 1000;
+		}
+
+		/* Make sure the current charge does not exceed the full charge */
+        	if (reporting_current > reporting_lastfull) {
+        		reporting_current = reporting_lastfull;
+        	}
+		
+		if (reporting_current < 0) {
+			reporting_current = 0;
+		}
+		
+		if (!(charging) && !(discharging)) {
+			reporting_rate = 0;
+		}
+		
+		if (reporting_lastfull > 0) {
+			new_percentage = ((double) reporting_current / (double) reporting_lastfull) * 100.0;	
+		}
+		if (new_percentage < 0) {
+			new_percentage = 0;
+		}
+		if (new_percentage > 100) {
+			new_percentage = 100;
+		}
+		
+		new_time_to_empty = estimate_time(reporting_rate, reporting_current, reporting_lastfull, discharging, charging);
+		if (new_time_to_empty < 0) { /* Need to do something more sane here */
+			new_time_to_empty = 0;
+		}
+
+		if (discharging)
+			new_state = UP_DEVICE_STATE_DISCHARGING;
+		else if (charging)
+			new_state = UP_DEVICE_STATE_CHARGING;
+
+		if (!discharging && !charging) {
+			if (new_percentage >= 99.0) {
+				new_state = UP_DEVICE_STATE_FULLY_CHARGED;
+			} else {
+				/* Really we should set UP_DEVICE_STATE_PENDING_CHARGE here, 
+				   but it seems that up_daemon can't sum up such device 
+				   and we end up in unkonw state, so let's say that we are charging */
+				new_state = UP_DEVICE_STATE_CHARGING;
+			}
+		}	 
+
+		if (cur_state != new_state ||
+			percentage != new_percentage ||
+			cur_time_to_empty != new_time_to_empty) {
+		                g_object_set (device,
+					"state", new_state,
+					"percentage", new_percentage,
+		                        "time-to-empty", new_time_to_empty,
+		                        "is-present", TRUE,
+       			                 (void*) NULL);
+				g_object_set (device,
+					"energy", ((gdouble) reporting_current)/1000.0,
+					"energy-full", ((gdouble) reporting_lastfull)/1000.0,
+					"energy-full-design", ((gdouble)reporting_design_capacity)/1000.0 ,
+					"energy-rate", ((gdouble) reporting_rate)/1000.0,
+					"energy-empty", ((gdouble) reporting_lowcap)/1000.0,
+					"voltage", (gdouble) present_voltage,
+					"capacity", new_percentage,
+					(void*) NULL);
+       			return TRUE;
+        	}
+	}
+	return FALSE;
+}
+
+static gboolean
+up_acpi_device_refresh(UpDevice* device)
+{
+	UpDeviceKind type;
+	gboolean ret;
+	g_object_get (device, "type", &type, NULL);
+
+	switch (type) {
+		case UP_DEVICE_KIND_LINE_POWER:
+			ret = up_backend_update_ac_state(device);
+			break;
+		case UP_DEVICE_KIND_BATTERY:
+			ret = up_backend_update_battery_state(device);
+			break;
+		default:
+			g_assert_not_reached ();
+			break;
+	}
+
+	g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL);
+
+	return TRUE;
+}
+
+/*
+ * Check the lid status, return TRUE if one was found, FALSE otherwise.
+ */
+static void
+up_backend_update_lid_status(UpDaemon *daemon)
+{
+	di_node_t root_node;
+	struct mdi_arg ma;
+        int state = 0;
+
+	ma.name = "lid";
+	ma.exact_match = TRUE;
+	ma.ctl = ACPI_DRV_IOC_LID_UPDATE;
+	ma.result = &state;
+	ma.device_path = NULL;
+	
+	errno = 0;
+	if((root_node = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) {
+		g_error("di_init() failed: %s", g_strerror(errno));
+		return;
+	}
+	di_walk_node(root_node, DI_WALK_CLDFIRST, &ma, minor_device_ioctl);
+	di_fini(root_node);
+	
+	up_daemon_set_lid_is_present (daemon, ma.present);
+	if (ma.present) 
+		up_daemon_set_lid_is_closed (daemon, state ? FALSE: TRUE);
+	if (ma.device_path)
+		g_free(ma.device_path);
+}
+
+static gboolean
+sysevent_iochannel_data(GIOChannel *source, GIOCondition condition, gpointer user_data)
+{
+        GError *err = NULL;
+        gchar *s = NULL;
+        gsize len;
+	UpBackend *backend;
+
+	backend = UP_BACKEND(user_data);
+
+        while (g_io_channel_read_line (sysevent_iochannel, &s, &len, NULL,
+            &err) == G_IO_STATUS_NORMAL) {
+		if (backend->priv->has_ac_device) {
+			up_acpi_device_refresh(backend->priv->ac);
+		}
+		if (backend->priv->has_bat_device) {
+                	up_acpi_device_refresh(backend->priv->battery);
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+simulate_iochannel_data (gpointer data) {
+	write(sysevent_pipe_fds[1],"\n", strlen("\n"));
+
+	return TRUE;
+}
+
+static void
+up_backend_sysevent_dev_handler(sysevent_t *ev) {
+	char *class;
+	char *subclass;
+	
+	if ((class = sysevent_get_class_name(ev)) == NULL)
+		return;
+	
+	if ((subclass = sysevent_get_subclass_name(ev)) == NULL)
+		return;
+	
+	if (strcmp(class, EC_PWRCTL) == 0) {
+		write(sysevent_pipe_fds[1],"\n", strlen("\n"));
+	}
+}
+
+static void
+up_backend_initialize_sysevent_handler(UpBackend *backend) {
+	const char *subcl[6];
+	GError *err = NULL;
+	
+	if (pipe(sysevent_pipe_fds) != 0) {
+		g_warning("Failed to initialize sysevent pipe");
+		return;
+	}
+
+	sysevent_iochannel = g_io_channel_unix_new (sysevent_pipe_fds[0]);
+	if (sysevent_iochannel == NULL) {
+		g_warning("Failed to create sysevent iochannel");
+                return;
+        }
+	g_io_channel_set_flags (sysevent_iochannel, G_IO_FLAG_NONBLOCK, &err);
+	g_io_add_watch (sysevent_iochannel, G_IO_IN, sysevent_iochannel_data, backend);
+
+	shp = sysevent_bind_handle(up_backend_sysevent_dev_handler);
+	if (shp == NULL) {
+		g_warning("Failed to initialize sysevent handler");
+		return;
+	}
+	
+	subcl[0] = ESC_PWRCTL_ADD;
+	subcl[1] = ESC_PWRCTL_REMOVE;
+	subcl[2] = ESC_PWRCTL_STATE_CHANGE;
+	subcl[3] = ESC_PWRCTL_BRIGHTNESS_UP;
+	subcl[4] = ESC_PWRCTL_BRIGHTNESS_DOWN;
+	subcl[5] = ESC_PWRCTL_POWER_BUTTON;
+	
+	if (sysevent_subscribe_event(shp, EC_PWRCTL, subcl, 6) != 0) {
+		g_warning("Failed to subscribe to EC_PWRCTL events");
+		sysevent_unbind_handle(shp);
+		return;
+	}
+}
+
+
+/**
+ * GObject class functions
+ **/
+
+/**
+ * up_backend_new:
+ *
+ * Return value: a new %UpBackend object.
+ **/
+UpBackend *
+up_backend_new (void)
+{
+	return g_object_new (UP_TYPE_BACKEND, NULL);
+}
+
+/**
+ * up_backend_class_init:
+ * @klass: The UpBackendClass
+ **/
+static void
+up_backend_class_init (UpBackendClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = up_backend_finalize;
+
+	signals [SIGNAL_DEVICE_ADDED] =
+		g_signal_new ("device-added",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (UpBackendClass, device_added),
+			      NULL, NULL, NULL,
+			      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 (UpBackendClass, device_removed),
+			      NULL, NULL, NULL,
+			      G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+
+	g_type_class_add_private (klass, sizeof (UpBackendPrivate));
+}
+
+/**
+ * up_backend_init:
+ **/
+static void
+up_backend_init (UpBackend *backend)
+{
+	UpDeviceClass *device_class;
+	char *devpath = NULL;
+	gint64 current_time;
+
+	backend->priv = UP_BACKEND_GET_PRIVATE (backend);
+
+	devpath = up_backend_get_ac_device_path(ACPI_DRV_TYPE_AC);
+	if (devpath) {
+		backend->priv->has_ac_device = TRUE;
+		g_free(devpath);
+	} else {
+		backend->priv->has_ac_device = FALSE;
+	}
+
+	devpath = up_backend_get_ac_device_path(ACPI_DRV_TYPE_CBAT);
+	if (devpath) {
+		backend->priv->has_bat_device = TRUE;
+		g_free(devpath);
+	} else {
+		backend->priv->has_bat_device = FALSE;
+	}
+
+	current_time = g_get_real_time () / G_USEC_PER_SEC;
+	if (backend->priv->has_ac_device)
+	{
+		backend->priv->ac = UP_DEVICE(up_device_new());
+		device_class = UP_DEVICE_GET_CLASS (backend->priv->ac);
+		device_class->get_on_battery = up_acpi_device_get_on_battery;
+		device_class->get_online = up_acpi_device_get_online;
+		device_class->refresh = up_acpi_device_refresh;
+
+		/* setup dummy */
+		g_object_set (backend->priv->ac,
+			      "type", UP_DEVICE_KIND_LINE_POWER,
+			      "online", TRUE,
+			      "power-supply", TRUE,
+			      "update-time", (guint64) current_time,
+			      (void*) NULL);
+	} 
+
+	if (backend->priv->has_bat_device)
+	{
+		backend->priv->battery = UP_DEVICE(up_device_new ());
+		device_class = UP_DEVICE_GET_CLASS (backend->priv->battery);
+		device_class->get_on_battery = up_acpi_device_get_on_battery;
+		device_class->get_online = up_acpi_device_get_online;
+		device_class->refresh = up_acpi_device_refresh;
+
+		/* setup dummy */
+		g_object_set (backend->priv->battery,
+			      "type", UP_DEVICE_KIND_BATTERY,
+			      "power-supply", TRUE,
+			      "is-present", TRUE,
+			      "is-rechargeable", TRUE,
+			      "has-history", TRUE,
+			      "state", UP_DEVICE_STATE_UNKNOWN,
+			      "percentage", 0.0f,
+			      "time-to-empty", (gint64) 0,
+			      "update-time", (guint64) current_time,
+			      (void*) NULL);
+	}
+
+	if (backend->priv->has_bat_device || backend->priv->has_ac_device) {
+		/* Initialize sysevent handler */
+		up_backend_initialize_sysevent_handler(backend);
+		/* Some acpi devices are broken enough to avoid generating
+			EC_PWRCTL events, so we force update once per POLL_INTERVAL */
+		g_timeout_add (POLL_INTERVAL, simulate_iochannel_data, NULL);
+		
+	}
+
+	backend->priv->config = up_config_new ();
+	backend->priv->seat_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+									   0,
+									   NULL,
+									   CONSOLEKIT2_DBUS_NAME,
+									   CONSOLEKIT2_DBUS_PATH,
+									   CONSOLEKIT2_DBUS_INTERFACE,
+									   NULL,
+									   NULL);
+}
+/**
+ * up_backend_finalize:
+ **/
+static void
+up_backend_finalize (GObject *object)
+{
+	UpBackend *backend;
+
+	g_return_if_fail (UP_IS_BACKEND (object));
+
+	backend = UP_BACKEND (object);
+
+	sysevent_unbind_handle(shp);
+	shp = NULL;
+
+	g_object_unref (backend->priv->config);
+	if (backend->priv->daemon != NULL)
+		g_object_unref (backend->priv->daemon);
+	if (backend->priv->battery != NULL)
+		g_object_unref (backend->priv->battery);
+	if (backend->priv->ac != NULL)
+		g_object_unref (backend->priv->ac);
+	g_clear_object (&backend->priv->seat_manager_proxy);
+
+	G_OBJECT_CLASS (up_backend_parent_class)->finalize (object);
+}
+
+static int
+minor_device_ioctl(di_node_t node, void *arg)
+{
+	struct mdi_arg *st;
+	char *dn;
+	
+	st = (struct mdi_arg*) arg;
+	
+	st->present = FALSE;
+	st->success = FALSE;
+	
+	dn=di_driver_name(node);
+	if (dn && !strcmp("acpi_drv",dn)) {
+		di_minor_t minor;
+		
+		minor = DI_MINOR_NIL;
+		while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
+			char *dp, *fdp;
+			int fd;
+			char *mname;
+			
+			dp=di_devfs_path(node);
+			if (!dp) {
+				g_warning("Couldn't get path for acpi_drv device");
+				continue;
+			}
+			
+			mname = di_minor_name(minor);
+			if ((st->exact_match && strcmp(st->name, mname) != 0) ||
+			    (!st->exact_match && strncmp(st->name, mname, strlen(st->name)) != 0)) {
+				g_debug("Device %s is not a %s. Skipping.", mname, st->name);
+				di_devfs_path_free(dp);
+				continue;
+			}
+			fdp = g_strconcat(DEVFS_PREFIX, dp,":", di_minor_name(minor), NULL);
+			if (!fdp) {
+				g_warning("Couldn't allocate memory");
+				di_devfs_path_free(dp);
+				continue;
+			}
+			
+			fd = open(fdp, O_RDONLY);
+			if (fd == -1) {
+				g_warning("Couldn't open %s device", fdp);
+				di_devfs_path_free(dp);
+				g_free(fdp);
+				continue;
+			}
+			
+			st->present = TRUE;
+			st->device_path = fdp;
+			
+			if (ioctl(fd, st->ctl, st->result) < 0) {          
+				st->success = FALSE;
+				g_warning("ioctl %d to device %s failed", st->ctl, fdp);
+			} else {
+				st->success = TRUE;
+			}
+			
+			close(fd);
+			di_devfs_path_free(dp);
+			return DI_WALK_TERMINATE;
+		}
+	}
+	return DI_WALK_CONTINUE;
+}
+
+static char*
+up_backend_get_ac_device_path(enum acpi_drv_type device)
+{
+	di_node_t root_node;
+	
+	struct mdi_arg ma;
+	int state = 0;
+	acpi_bif_t bif;
+	
+	switch (device) {
+		case ACPI_DRV_TYPE_CBAT:
+			ma.name = "battery";
+			ma.ctl = ACPI_DRV_IOC_INFO;
+			ma.exact_match = FALSE;
+			/* We don't do it as we ignore result anyway */
+			/* memset(&bif, 0, sizeof(bif));*/
+			ma.result = &bif;
+			break;
+		case ACPI_DRV_TYPE_AC:
+			ma.name = "ac";
+			ma.ctl = ACPI_DRV_IOC_POWER_STATUS;
+			ma.exact_match = FALSE;
+			ma.result = &state;
+			break;
+		default:
+			return NULL;
+	}
+
+	ma.device_path = NULL;
+	
+	errno = 0;
+	if((root_node = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) {
+		g_error("di_init() failed: %s", g_strerror(errno));
+		return FALSE;
+	}
+	di_walk_node(root_node, DI_WALK_CLDFIRST, &ma, minor_device_ioctl);
+	di_fini(root_node);
+	return ma.device_path;
+}
+
+static int
+up_backend_acpi_get_ac_online()
+{
+	di_node_t root_node;
+	
+	struct mdi_arg ma;
+	int state = 0;
+	
+	ma.name = "ac";
+	ma.exact_match = FALSE;
+	ma.ctl = ACPI_DRV_IOC_POWER_STATUS;
+	ma.result = &state;
+	ma.device_path = NULL;
+	
+	errno = 0;
+	if((root_node = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) {
+		g_error("di_init() failed: %s", g_strerror(errno));
+		return FALSE;
+	}
+	di_walk_node(root_node, DI_WALK_CLDFIRST, &ma, minor_device_ioctl);
+	di_fini(root_node);
+	if (ma.device_path)
+		g_free(ma.device_path);
+	if (!ma.success)
+		state = -1;
+	return state;
+}
+
+static int
+estimate_time(int charge_rate, int current_charge, int last_fullcharge, int is_discharging, int is_charging)
+{
+	int rem_secs = 0;
+	if (charge_rate > 0 && last_fullcharge >= current_charge && (is_discharging ^ is_charging)) {
+		if (is_discharging) {
+			rem_secs = ((double) current_charge / (double) charge_rate) * 60 * 60;
+		} else {
+			rem_secs = (((double)(last_fullcharge - current_charge))/ (double) charge_rate) * 60 * 60;
+		}
+		return rem_secs;
+	} else {
+		/* Can't estimate time */
+		return -1;
+	} 
+}
diff -urN upower-0.99.4-orig/src/illumos/up-native.c upower-0.99.4/src/illumos/up-native.c
--- upower-0.99.4-orig/src/illumos/up-native.c	1970-01-01 03:00:00.000000000 +0000
+++ upower-0.99.4/src/illumos/up-native.c	2017-12-26 13:49:53.077225711 +0000
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Landry Breuil <landry@openbsd.org>
+ * Copyright (C) 2018 Alexander Pyhalov <apyhalov@gmail.com>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "up-acpi-native.h"
+#include "up-native.h"
+#include <unistd.h> /* close() */
+#include <string.h> /* strcmp() */
+
+G_DEFINE_TYPE (UpAcpiNative, up_acpi_native, G_TYPE_OBJECT)
+
+static void
+up_acpi_native_class_init (UpAcpiNativeClass *klass)
+{
+}
+
+static void
+up_acpi_native_init (UpAcpiNative *self)
+{
+	self->path = NULL;
+}
+
+UpAcpiNative *
+up_acpi_native_new(const gchar * path)
+{
+	UpAcpiNative *native;
+	native = UP_ACPI_NATIVE (g_object_new (UP_TYPE_ACPI_NATIVE, NULL));
+	native->path = g_strdup(path);
+	return native;
+}
+
+const gchar *
+up_acpi_native_get_path(UpAcpiNative * native)
+{
+	return native->path;
+}
+
+/**
+ * up_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. "/devices/pseudo/acpi_drv@0:battery0"
+ **/
+const gchar *
+up_native_get_native_path (GObject *object)
+{
+	return up_acpi_native_get_path (UP_ACPI_NATIVE (object));
+}