1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2015 Dominika Hodovska <dhodovsk@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "config.h"
21
22 #include <glib/gi18n.h>
23 #include <blockdev/kbd.h>
24
25 #include <src/udisksdaemon.h>
26 #include <src/udisksdaemonutil.h>
27 #include <src/udiskslogging.h>
28 #include <src/udiskslinuxblock.h>
29 #include <src/udiskslinuxblockobject.h>
30 #include "udiskslinuxblockbcache.h"
31 #include "udiskslinuxmanagerbcache.h"
32 #include "udiskslinuxmodulebcache.h"
33
34 /**
35 * SECTION: udiskslinuxmanagerbcache
36 * @title: UDisksLinuxManagerBcache
37 * @short_description: Linux implementation of #UDisksLinuxManagerBcache
38 *
39 * This type provides an implementation of the #UDisksLinuxManagerBcache
40 * interface on Linux.
41 */
42
43 /**
44 * UDisksLinuxManagerBcache:
45 *
46 * The #UDisksLinuxManagerBcache structure contains only private data and
47 * should only be accessed using the provided API.
48 */
49
50 struct _UDisksLinuxManagerBcache {
51 UDisksManagerBcacheSkeleton parent_instance;
52
53 UDisksLinuxModuleBcache *module;
54 };
55
56 struct _UDisksLinuxManagerBcacheClass {
57 UDisksManagerBcacheSkeletonClass parent_class;
58 };
59
60 static void udisks_linux_manager_bcache_iface_init (UDisksManagerBcacheIface *iface);
61
62 G_DEFINE_TYPE_WITH_CODE (UDisksLinuxManagerBcache, udisks_linux_manager_bcache, UDISKS_TYPE_MANAGER_BCACHE_SKELETON,
63 G_IMPLEMENT_INTERFACE (UDISKS_TYPE_MANAGER_BCACHE, udisks_linux_manager_bcache_iface_init));
64
65 enum
66 {
67 PROP_0,
68 PROP_MODULE,
69 N_PROPERTIES
70 };
71
72 static void
udisks_linux_manager_bcache_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)73 udisks_linux_manager_bcache_get_property (GObject *object,
74 guint property_id,
75 GValue *value,
76 GParamSpec *pspec)
77 {
78 UDisksLinuxManagerBcache *manager = UDISKS_LINUX_MANAGER_BCACHE (object);
79
80 switch (property_id)
81 {
82 case PROP_MODULE:
83 g_value_set_object (value, udisks_linux_manager_bcache_get_module (manager));
84 break;
85
86 default:
87 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
88 break;
89 }
90 }
91
92 static void
udisks_linux_manager_bcache_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)93 udisks_linux_manager_bcache_set_property (GObject *object,
94 guint property_id,
95 const GValue *value,
96 GParamSpec *pspec)
97 {
98 UDisksLinuxManagerBcache *manager = UDISKS_LINUX_MANAGER_BCACHE (object);
99
100 switch (property_id)
101 {
102 case PROP_MODULE:
103 g_assert (manager->module == NULL);
104 manager->module = g_value_dup_object (value);
105 break;
106
107 default:
108 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
109 break;
110 }
111 }
112
113 static void
udisks_linux_manager_bcache_finalize(GObject * object)114 udisks_linux_manager_bcache_finalize (GObject *object)
115 {
116 UDisksLinuxManagerBcache *manager = UDISKS_LINUX_MANAGER_BCACHE (object);
117
118 g_object_unref (manager->module);
119
120 if (G_OBJECT_CLASS (udisks_linux_manager_bcache_parent_class))
121 G_OBJECT_CLASS (udisks_linux_manager_bcache_parent_class)->finalize (object);
122 }
123
124 static void
udisks_linux_manager_bcache_class_init(UDisksLinuxManagerBcacheClass * klass)125 udisks_linux_manager_bcache_class_init (UDisksLinuxManagerBcacheClass *klass)
126 {
127 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
128
129 gobject_class->get_property = udisks_linux_manager_bcache_get_property;
130 gobject_class->set_property = udisks_linux_manager_bcache_set_property;
131 gobject_class->finalize = udisks_linux_manager_bcache_finalize;
132
133 /**
134 * UDisksLinuxManagerBcache:module:
135 *
136 * The #UDisksModule for the object.
137 */
138 g_object_class_install_property (gobject_class,
139 PROP_MODULE,
140 g_param_spec_object ("module",
141 "Module",
142 "The module for the object",
143 UDISKS_TYPE_LINUX_MODULE_BCACHE,
144 G_PARAM_READABLE |
145 G_PARAM_WRITABLE |
146 G_PARAM_CONSTRUCT_ONLY |
147 G_PARAM_STATIC_STRINGS));
148 }
149
150 static void
udisks_linux_manager_bcache_init(UDisksLinuxManagerBcache * self)151 udisks_linux_manager_bcache_init (UDisksLinuxManagerBcache *self)
152 {
153 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (self),
154 G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
155 }
156
157 /**
158 * udisks_linux_manager_bcache_new:
159 * @module: A #UDisksLinuxModuleBcache.
160 *
161 * Creates a new #UDisksLinuxManagerBcache instance.
162 *
163 * Returns: A new #UDisksLinuxManagerBcache. Free with g_object_unref ().
164 */
165 UDisksLinuxManagerBcache *
udisks_linux_manager_bcache_new(UDisksLinuxModuleBcache * module)166 udisks_linux_manager_bcache_new (UDisksLinuxModuleBcache *module)
167 {
168 g_return_val_if_fail (UDISKS_IS_LINUX_MODULE_BCACHE (module), NULL);
169 return UDISKS_LINUX_MANAGER_BCACHE (g_object_new (UDISKS_TYPE_LINUX_MANAGER_BCACHE,
170 "module", module,
171 NULL));
172 }
173
174 /**
175 * udisks_linux_manager_bcache_get_module:
176 * @manager: A #UDisksLinuxManagerBcache.
177 *
178 * Gets the module used by @manager.
179 *
180 * Returns: A #UDisksLinuxModuleBcache. Do not free, the object is owned by @manager.
181 */
182 UDisksLinuxModuleBcache *
udisks_linux_manager_bcache_get_module(UDisksLinuxManagerBcache * manager)183 udisks_linux_manager_bcache_get_module (UDisksLinuxManagerBcache *manager)
184 {
185 g_return_val_if_fail (UDISKS_IS_LINUX_MANAGER_BCACHE (manager), NULL);
186 return manager->module;
187 }
188
189 static UDisksObject *
wait_for_bcache_object(UDisksDaemon * daemon,gpointer user_data)190 wait_for_bcache_object (UDisksDaemon *daemon,
191 gpointer user_data)
192 {
193 UDisksObject *object = NULL;
194 UDisksBlock *block = NULL;
195
196 object = udisks_daemon_find_block_by_device_file (daemon, (const gchar *) user_data);
197 if (object == NULL)
198 goto out;
199
200 block = udisks_object_peek_block (object);
201 if (block == NULL)
202 {
203 g_clear_object (&object);
204 goto out;
205 }
206
207 out:
208 return object;
209 }
210
211 static gboolean
handle_bcache_create(UDisksManagerBcache * object,GDBusMethodInvocation * invocation,const gchar * arg_backing_dev,const gchar * arg_cache_dev,GVariant * options)212 handle_bcache_create (UDisksManagerBcache *object,
213 GDBusMethodInvocation *invocation,
214 const gchar *arg_backing_dev,
215 const gchar *arg_cache_dev,
216 GVariant *options)
217 {
218 UDisksLinuxManagerBcache *manager = UDISKS_LINUX_MANAGER_BCACHE (object);
219 UDisksDaemon *daemon;
220 UDisksObject *backing_dev_object = NULL;
221 UDisksBlock *backing_dev_block = NULL;
222 gchar *backing_dev_path = NULL;
223 UDisksObject *cache_dev_object = NULL;
224 UDisksBlock *cache_dev_block = NULL;
225 gchar *cache_dev_path = NULL;
226 gchar *bcache_name = NULL;
227 gchar *bcache_file = NULL;
228 UDisksObject *bcache_object = NULL;
229 GError *error = NULL;
230
231 daemon = udisks_module_get_daemon (UDISKS_MODULE (manager->module));
232
233 /* Policy check */
234 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
235 NULL,
236 BCACHE_POLICY_ACTION_ID,
237 options,
238 N_("Authentication is required to create bcache device."),
239 invocation);
240
241 /* get path for the backing device */
242 backing_dev_object = udisks_daemon_find_object (daemon, arg_backing_dev);
243 if (backing_dev_object == NULL)
244 {
245 g_dbus_method_invocation_return_error (invocation,
246 UDISKS_ERROR,
247 UDISKS_ERROR_FAILED,
248 "Invalid object path %s",
249 arg_backing_dev);
250 goto out;
251 }
252
253 backing_dev_block = udisks_object_get_block (backing_dev_object);
254 if (backing_dev_block == NULL)
255 {
256 g_dbus_method_invocation_return_error (invocation,
257 UDISKS_ERROR,
258 UDISKS_ERROR_FAILED,
259 "Object path %s is not a block device",
260 arg_backing_dev);
261 goto out;
262 }
263
264 backing_dev_path = udisks_block_dup_device (backing_dev_block);
265
266 /* get path for the cache device */
267 cache_dev_object = udisks_daemon_find_object (daemon, arg_cache_dev);
268 if (cache_dev_object == NULL)
269 {
270 g_dbus_method_invocation_return_error (invocation,
271 UDISKS_ERROR,
272 UDISKS_ERROR_FAILED,
273 "Invalid object path %s",
274 arg_cache_dev);
275 goto out;
276 }
277
278 cache_dev_block = udisks_object_get_block (cache_dev_object);
279 if (cache_dev_block == NULL)
280 {
281 g_dbus_method_invocation_return_error (invocation,
282 UDISKS_ERROR,
283 UDISKS_ERROR_FAILED,
284 "Object path %s is not a block device",
285 arg_cache_dev);
286 goto out;
287 }
288
289 cache_dev_path = udisks_block_dup_device (cache_dev_block);
290
291 /* XXX: the type casting below looks like a bug in libblockdev */
292 if (! bd_kbd_bcache_create (backing_dev_path, cache_dev_path, NULL, (const gchar **) &bcache_name, &error))
293 {
294 g_dbus_method_invocation_take_error (invocation, error);
295 goto out;
296 }
297
298 bcache_file = g_strdup_printf ("/dev/%s", bcache_name);
299 /* sit and wait for the bcache object to show up */
300 bcache_object = udisks_daemon_wait_for_object_sync (daemon,
301 wait_for_bcache_object,
302 bcache_file,
303 NULL,
304 UDISKS_DEFAULT_WAIT_TIMEOUT,
305 &error);
306
307 if (bcache_object == NULL)
308 {
309 g_prefix_error (&error,
310 "Error waiting for bcache object after creating '%s': ",
311 bcache_name);
312 g_dbus_method_invocation_take_error (invocation, error);
313 goto out;
314 }
315
316 udisks_manager_bcache_complete_bcache_create (object,
317 invocation,
318 g_dbus_object_get_object_path (G_DBUS_OBJECT (bcache_object)));
319 out:
320 g_free (backing_dev_path);
321 g_free (cache_dev_path);
322 g_free (bcache_name);
323 g_free (bcache_file);
324 g_clear_object (&bcache_object);
325 g_clear_object (&backing_dev_object);
326 g_clear_object (&backing_dev_block);
327 g_clear_object (&cache_dev_object);
328 g_clear_object (&cache_dev_block);
329
330 return TRUE;
331 }
332
333 static void
udisks_linux_manager_bcache_iface_init(UDisksManagerBcacheIface * iface)334 udisks_linux_manager_bcache_iface_init (UDisksManagerBcacheIface *iface)
335 {
336 iface->handle_bcache_create = handle_bcache_create;
337 }
338