1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
From 932a6a39e35754be571e1274aec4730fd42dba13 Mon Sep 17 00:00:00 2001
From: Martin Pitt <martin.pitt@ubuntu.com>
Date: Wed, 18 May 2016 09:22:43 +0200
Subject: lib: Add proper error and cancellable handling to UpClient
constructor
A GObject's _init() should never fail or block, but this is currently the case
as up_client_init() connects to upowerd on D-Bus. Convert this to the GInitable
interface and provide a new constructor up_client_new_full() which accepts a
GCancellable and GError, so that clients can do proper error handling
and reporting.
This changes up_client_new() to return NULL when connecting to upowerd fails.
This provides a more well-defined behaviour in this case as clients can check
for this and our methods stop segfaulting as they have checks like
g_return_val_if_fail (UP_IS_CLIENT (client), ...)
Previously we returned a valid object, but trying to call any method on it
segfaulted due to the NULL D-Bus proxy, so client code had no chance to check
whether the UpClient object was really valid.
https://bugs.freedesktop.org/show_bug.cgi?id=95350
diff --git a/libupower-glib/up-client.c b/libupower-glib/up-client.c
index 5b2218f..adc0b9b 100644
--- a/libupower-glib/up-client.c
+++ b/libupower-glib/up-client.c
@@ -39,9 +39,10 @@
#include "up-daemon-generated.h"
#include "up-device.h"
-static void up_client_class_init (UpClientClass *klass);
-static void up_client_init (UpClient *client);
-static void up_client_finalize (GObject *object);
+static void up_client_class_init (UpClientClass *klass);
+static void up_client_initable_iface_init (GInitableIface *iface);
+static void up_client_init (UpClient *client);
+static void up_client_finalize (GObject *object);
#define UP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_CLIENT, UpClientPrivate))
@@ -73,7 +74,8 @@ enum {
static guint signals [UP_CLIENT_LAST_SIGNAL] = { 0 };
static gpointer up_client_object = NULL;
-G_DEFINE_TYPE (UpClient, up_client, G_TYPE_OBJECT)
+G_DEFINE_TYPE_WITH_CODE (UpClient, up_client, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, up_client_initable_iface_init))
/**
* up_client_get_devices:
@@ -434,11 +436,10 @@ up_client_class_init (UpClientClass *klass)
* up_client_init:
* @client: This class instance
*/
-static void
-up_client_init (UpClient *client)
+static gboolean
+up_client_initable_init (GInitable *initable, GCancellable *cancellable, GError **error)
{
- GError *error = NULL;
-
+ UpClient *client = UP_CLIENT (initable);
client->priv = UP_CLIENT_GET_PRIVATE (client);
/* connect to main interface */
@@ -446,13 +447,10 @@ up_client_init (UpClient *client)
G_DBUS_PROXY_FLAGS_NONE,
"org.freedesktop.UPower",
"/org/freedesktop/UPower",
- NULL,
- &error);
- if (client->priv->proxy == NULL) {
- g_warning ("Couldn't connect to proxy: %s", error->message);
- g_error_free (error);
- return;
- }
+ cancellable,
+ error);
+ if (client->priv->proxy == NULL)
+ return FALSE;
/* all callbacks */
g_signal_connect (client->priv->proxy, "device-added",
@@ -461,6 +459,23 @@ up_client_init (UpClient *client)
G_CALLBACK (up_device_removed_cb), client);
g_signal_connect (client->priv->proxy, "notify",
G_CALLBACK (up_client_notify_cb), client);
+
+ return TRUE;
+}
+
+static void
+up_client_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = up_client_initable_init;
+}
+
+/*
+ * up_client_init:
+ * @client: This class instance
+ */
+static void
+up_client_init (UpClient *client)
+{
}
/*
@@ -482,23 +497,52 @@ up_client_finalize (GObject *object)
}
/**
- * up_client_new:
+ * up_client_new_full:
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
*
- * Creates a new #UpClient object.
+ * Creates a new #UpClient object. If connecting to upowerd on D-Bus fails,
+ % this returns %NULL and sets @error.
*
- * Return value: a new UpClient object.
+ * Return value: a new UpClient object, or %NULL on failure.
*
- * Since: 0.9.0
+ * Since: 0.99.5
**/
UpClient *
-up_client_new (void)
+up_client_new_full (GCancellable *cancellable, GError **error)
{
if (up_client_object != NULL) {
g_object_ref (up_client_object);
} else {
- up_client_object = g_object_new (UP_TYPE_CLIENT, NULL);
- g_object_add_weak_pointer (up_client_object, &up_client_object);
+ up_client_object = g_initable_new (UP_TYPE_CLIENT, cancellable, error, NULL);
+ if (up_client_object)
+ g_object_add_weak_pointer (up_client_object, &up_client_object);
}
return UP_CLIENT (up_client_object);
}
+/**
+ * up_client_new:
+ *
+ * Creates a new #UpClient object. If connecting to upowerd on D-Bus fails,
+ * this returns %NULL and prints out a warning with the error message.
+ * Consider using up_client_new_full() instead which allows you to handle errors
+ * and cancelling long operations yourself.
+ *
+ * Return value: a new UpClient object, or %NULL on failure.
+ *
+ * Since: 0.9.0
+ **/
+UpClient *
+up_client_new (void)
+{
+ GError *error = NULL;
+ UpClient *client;
+ client = up_client_new_full (NULL, &error);
+ if (client == NULL) {
+ g_warning ("Couldn't connect to proxy: %s", error->message);
+ g_error_free (error);
+ }
+ return client;
+}
+
diff --git a/libupower-glib/up-client.h b/libupower-glib/up-client.h
index 79c2d9e..5b9af3c 100644
--- a/libupower-glib/up-client.h
+++ b/libupower-glib/up-client.h
@@ -72,6 +72,7 @@ typedef struct
/* general */
GType up_client_get_type (void);
UpClient *up_client_new (void);
+UpClient *up_client_new_full (GCancellable *cancellable, GError **error);
/* sync versions */
UpDevice * up_client_get_display_device (UpClient *client);
--
cgit v0.10.2
|