1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
4 * Copyright (C) 2016 Peter Hatina <phatina@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "config.h"
23 #include <glib/gi18n-lib.h>
24 #include <uuid.h>
25 #include <blockdev/blockdev.h>
26
27 #include "udiskslogging.h"
28 #include "udisksdaemon.h"
29 #include "udisksdaemonutil.h"
30 #include "udisksprovider.h"
31 #include "udiskslinuxprovider.h"
32 #include "udisksmountmonitor.h"
33 #include "udisksmount.h"
34 #include "udisksbasejob.h"
35 #include "udisksspawnedjob.h"
36 #include "udisksthreadedjob.h"
37 #include "udiskssimplejob.h"
38 #include "udisksstate.h"
39 #include "udiskscrypttabmonitor.h"
40 #include "udiskscrypttabentry.h"
41 #include "udiskslinuxblockobject.h"
42 #include "udiskslinuxdevice.h"
43 #include "udisksmodulemanager.h"
44 #include "udisksmodule.h"
45 #include "udisksconfigmanager.h"
46 #include "udiskslinuxmountoptions.h"
47
48 #ifdef HAVE_LIBMOUNT_UTAB
49 #include "udisksutabmonitor.h"
50 #endif
51
52 /**
53 * SECTION:udisksdaemon
54 * @title: UDisksDaemon
55 * @short_description: Main daemon object
56 *
57 * Object holding all global state.
58 */
59
60 typedef struct _UDisksDaemonClass UDisksDaemonClass;
61
62 /**
63 * UDisksDaemon:
64 *
65 * The #UDisksDaemon structure contains only private data and should
66 * only be accessed using the provided API.
67 */
68 struct _UDisksDaemon
69 {
70 GObject parent_instance;
71 GDBusConnection *connection;
72 GDBusObjectManagerServer *object_manager;
73
74 UDisksMountMonitor *mount_monitor;
75
76 UDisksLinuxProvider *linux_provider;
77
78 /* may be NULL if polkit is masked */
79 PolkitAuthority *authority;
80
81 UDisksState *state;
82
83 UDisksCrypttabMonitor *crypttab_monitor;
84
85 #ifdef HAVE_LIBMOUNT_UTAB
86 UDisksUtabMonitor *utab_monitor;
87 #endif
88
89 UDisksModuleManager *module_manager;
90
91 UDisksConfigManager *config_manager;
92
93 gboolean disable_modules;
94 gboolean force_load_modules;
95 gboolean uninstalled;
96 gboolean enable_tcrypt;
97 gchar *uuid;
98 };
99
100 struct _UDisksDaemonClass
101 {
102 GObjectClass parent_class;
103 };
104
105 enum
106 {
107 PROP_0,
108 PROP_CONNECTION,
109 PROP_OBJECT_MANAGER,
110 PROP_MOUNT_MONITOR,
111 PROP_CRYPTTAB_MONITOR,
112 PROP_MODULE_MANAGER,
113 PROP_CONFIG_MANAGER,
114 PROP_DISABLE_MODULES,
115 PROP_FORCE_LOAD_MODULES,
116 PROP_UNINSTALLED,
117 PROP_ENABLE_TCRYPT,
118 PROP_UUID,
119 };
120
121 G_DEFINE_TYPE (UDisksDaemon, udisks_daemon, G_TYPE_OBJECT);
122
123 static void
udisks_daemon_finalize(GObject * object)124 udisks_daemon_finalize (GObject *object)
125 {
126 UDisksDaemon *daemon = UDISKS_DAEMON (object);
127
128 udisks_state_stop_cleanup (daemon->state);
129
130 /* Modules use the monitors and try to reference them when cleaning up */
131 udisks_module_manager_unload_modules (daemon->module_manager);
132
133 g_clear_object (&daemon->authority);
134 g_object_unref (daemon->object_manager);
135 g_object_unref (daemon->linux_provider);
136 g_object_unref (daemon->connection);
137 g_object_unref (daemon->mount_monitor);
138 g_object_unref (daemon->crypttab_monitor);
139 #ifdef HAVE_LIBMOUNT_UTAB
140 g_object_unref (daemon->utab_monitor);
141 #endif
142 g_clear_object (&daemon->module_manager);
143
144 g_object_unref (daemon->state);
145 g_free (daemon->uuid);
146
147 g_clear_object (&daemon->config_manager);
148
149 if (G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize != NULL)
150 G_OBJECT_CLASS (udisks_daemon_parent_class)->finalize (object);
151 }
152
153 static void
udisks_daemon_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)154 udisks_daemon_get_property (GObject *object,
155 guint prop_id,
156 GValue *value,
157 GParamSpec *pspec)
158 {
159 UDisksDaemon *daemon = UDISKS_DAEMON (object);
160
161 switch (prop_id)
162 {
163 case PROP_CONNECTION:
164 g_value_set_object (value, udisks_daemon_get_connection (daemon));
165 break;
166
167 case PROP_OBJECT_MANAGER:
168 g_value_set_object (value, udisks_daemon_get_object_manager (daemon));
169 break;
170
171 case PROP_MOUNT_MONITOR:
172 g_value_set_object (value, udisks_daemon_get_mount_monitor (daemon));
173 break;
174
175 case PROP_CRYPTTAB_MONITOR:
176 g_value_set_object (value, udisks_daemon_get_crypttab_monitor (daemon));
177 break;
178
179 case PROP_MODULE_MANAGER:
180 g_value_set_object (value, udisks_daemon_get_module_manager (daemon));
181 break;
182
183 case PROP_CONFIG_MANAGER:
184 g_value_set_object (value, udisks_daemon_get_config_manager (daemon));
185 break;
186
187 case PROP_DISABLE_MODULES:
188 g_value_set_boolean (value, udisks_daemon_get_disable_modules (daemon));
189 break;
190
191 case PROP_FORCE_LOAD_MODULES:
192 g_value_set_boolean (value, udisks_daemon_get_force_load_modules (daemon));
193 break;
194
195 case PROP_UNINSTALLED:
196 g_value_set_boolean (value, udisks_daemon_get_uninstalled (daemon));
197 break;
198
199 case PROP_ENABLE_TCRYPT:
200 g_value_set_boolean (value, udisks_daemon_get_enable_tcrypt (daemon));
201 break;
202
203 case PROP_UUID:
204 g_value_set_string (value, udisks_daemon_get_uuid (daemon));
205 break;
206
207 default:
208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 break;
210 }
211 }
212
213 static void
udisks_daemon_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)214 udisks_daemon_set_property (GObject *object,
215 guint prop_id,
216 const GValue *value,
217 GParamSpec *pspec)
218 {
219 UDisksDaemon *daemon = UDISKS_DAEMON (object);
220 const gchar *s;
221 uuid_t uu;
222
223 switch (prop_id)
224 {
225 case PROP_CONNECTION:
226 g_assert (daemon->connection == NULL);
227 daemon->connection = g_value_dup_object (value);
228 break;
229
230 case PROP_DISABLE_MODULES:
231 daemon->disable_modules = g_value_get_boolean (value);
232 break;
233
234 case PROP_FORCE_LOAD_MODULES:
235 daemon->force_load_modules = g_value_get_boolean (value);
236 break;
237
238 case PROP_UNINSTALLED:
239 daemon->uninstalled = g_value_get_boolean (value);
240 break;
241
242 case PROP_ENABLE_TCRYPT:
243 daemon->enable_tcrypt = g_value_get_boolean (value);
244 break;
245
246 case PROP_UUID:
247 s = g_value_get_string (value);
248 if (s != NULL && uuid_parse (s, uu) == 0)
249 {
250 g_free (daemon->uuid);
251 daemon->uuid = g_strdup (s);
252 }
253 else
254 g_warning ("Invalid UUID string '%s'", s);
255 break;
256
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259 break;
260 }
261 }
262
263 static void
udisks_daemon_init(UDisksDaemon * daemon)264 udisks_daemon_init (UDisksDaemon *daemon)
265 {
266 }
267
268 static void
mount_monitor_on_mount_removed(UDisksMountMonitor * monitor,UDisksMount * mount,gpointer user_data)269 mount_monitor_on_mount_removed (UDisksMountMonitor *monitor,
270 UDisksMount *mount,
271 gpointer user_data)
272 {
273 UDisksDaemon *daemon = UDISKS_DAEMON (user_data);
274 udisks_state_check (daemon->state);
275 }
276
277 static gboolean
load_modules_in_idle_cb(gpointer user_data)278 load_modules_in_idle_cb (gpointer user_data)
279 {
280 UDisksDaemon *daemon = UDISKS_DAEMON (user_data);
281
282 /* clear the state file, loading all modules anyway */
283 udisks_state_clear_modules (daemon->state);
284
285 udisks_module_manager_load_modules (daemon->module_manager);
286
287 return G_SOURCE_REMOVE;
288 }
289
290 static gboolean
check_modules_state_in_idle_cb(gpointer user_data)291 check_modules_state_in_idle_cb (gpointer user_data)
292 {
293 UDisksDaemon *daemon = UDISKS_DAEMON (user_data);
294 gchar **modules;
295 gchar **l;
296 GError *error = NULL;
297
298 modules = udisks_state_get_modules (daemon->state);
299
300 /* first clear the state file */
301 udisks_state_clear_modules (daemon->state);
302
303 if (modules)
304 {
305 if (*modules)
306 g_warning ("Unclean shutdown detected, reloading modules from previous session.");
307
308 for (l = modules; l && *l; l++)
309 if (! udisks_module_manager_load_single_module (daemon->module_manager, *l, &error))
310 {
311 g_warning ("Error re-initializing module %s: %s", *l, error->message);
312 g_clear_error (&error);
313 }
314
315 g_strfreev (modules);
316 }
317
318 return G_SOURCE_REMOVE;
319 }
320
321 static void
udisks_daemon_constructed(GObject * object)322 udisks_daemon_constructed (GObject *object)
323 {
324 UDisksDaemon *daemon = UDISKS_DAEMON (object);
325 GError *error;
326 gboolean ret = FALSE;
327 gchar uuid_buf[UUID_STR_LEN] = {0};
328 uuid_t uuid;
329
330 /* NULL means no specific so_name (implementation) */
331 BDPluginSpec part_plugin = {BD_PLUGIN_PART, NULL};
332 BDPluginSpec swap_plugin = {BD_PLUGIN_SWAP, NULL};
333 BDPluginSpec loop_plugin = {BD_PLUGIN_LOOP, NULL};
334 BDPluginSpec mdraid_plugin = {BD_PLUGIN_MDRAID, NULL};
335 BDPluginSpec fs_plugin = {BD_PLUGIN_FS, NULL};
336 BDPluginSpec crypto_plugin = {BD_PLUGIN_CRYPTO, NULL};
337
338 /* The core daemon needs the part, swap, loop, mdraid, fs and crypto plugins.
339 Additional plugins are required by various modules, but they make sure
340 plugins are loaded themselves. */
341 BDPluginSpec *plugins[] = {&part_plugin, &swap_plugin, &loop_plugin, &mdraid_plugin,
342 &fs_plugin, &crypto_plugin, NULL};
343 BDPluginSpec **plugin_p = NULL;
344 error = NULL;
345
346 /* Skip runtime dependency checks when initializing libblockdev. Plugin
347 shouldn't fail to load just because some if its dependencies is missing.
348 */
349 ret = bd_switch_init_checks (FALSE, &error);
350 if (!ret)
351 {
352 udisks_error ("Error initializing libblockdev library: %s (%s, %d)",
353 error->message, g_quark_to_string (error->domain), error->code);
354 g_clear_error (&error);
355 }
356
357 ret = bd_try_init (plugins, NULL, NULL, &error);
358 if (!ret)
359 {
360 if (error)
361 {
362 udisks_error ("Error initializing libblockdev library: %s (%s, %d)",
363 error->message, g_quark_to_string (error->domain), error->code);
364 g_clear_error (&error);
365 }
366 else
367 {
368 /* a missing plugin is okay, calling functions from it will fail, but
369 until that happens, life will just be great */
370 for (plugin_p=plugins; *plugin_p; plugin_p++)
371 if (!bd_is_plugin_available ((*plugin_p)->name))
372 udisks_warning ("Failed to load the '%s' libblockdev plugin",
373 bd_get_plugin_name ((*plugin_p)->name));
374 }
375 }
376
377 /* Generate global UUID */
378 uuid_generate (uuid);
379 uuid_unparse (uuid, &uuid_buf[0]);
380 daemon->uuid = g_strdup (uuid_buf);
381
382 daemon->authority = polkit_authority_get_sync (NULL, &error);
383 if (daemon->authority == NULL)
384 {
385 udisks_critical ("Error initializing polkit authority: %s (%s, %d)",
386 error->message, g_quark_to_string (error->domain), error->code);
387 g_clear_error (&error);
388 }
389
390 daemon->object_manager = g_dbus_object_manager_server_new ("/org/freedesktop/UDisks2");
391
392 if (!g_file_test ("/run/udisks2", G_FILE_TEST_IS_DIR))
393 {
394 if (g_mkdir_with_parents ("/run/udisks2", 0700) != 0)
395 {
396 udisks_critical ("Error creating directory %s: %m", "/run/udisks2");
397 }
398 }
399
400 if (!g_file_test (PACKAGE_LOCALSTATE_DIR "/lib/udisks2", G_FILE_TEST_IS_DIR))
401 {
402 if (g_mkdir_with_parents (PACKAGE_LOCALSTATE_DIR "/lib/udisks2", 0700) != 0)
403 {
404 udisks_critical ("Error creating directory %s: %m", PACKAGE_LOCALSTATE_DIR "/lib/udisks2");
405 }
406 }
407
408
409 if (! daemon->uninstalled)
410 {
411 daemon->config_manager = udisks_config_manager_new ();
412 daemon->module_manager = udisks_module_manager_new (daemon);
413 }
414 else
415 {
416 daemon->config_manager = udisks_config_manager_new_uninstalled ();
417 daemon->module_manager = udisks_module_manager_new_uninstalled (daemon);
418 }
419
420 daemon->mount_monitor = udisks_mount_monitor_new ();
421
422 daemon->state = udisks_state_new (daemon);
423
424 g_signal_connect (daemon->mount_monitor,
425 "mount-removed",
426 G_CALLBACK (mount_monitor_on_mount_removed),
427 daemon);
428
429 daemon->crypttab_monitor = udisks_crypttab_monitor_new ();
430 #ifdef HAVE_LIBMOUNT_UTAB
431 daemon->utab_monitor = udisks_utab_monitor_new ();
432 #endif
433
434 /* now add providers */
435 daemon->linux_provider = udisks_linux_provider_new (daemon);
436 udisks_provider_start (UDISKS_PROVIDER (daemon->linux_provider));
437
438 /* fill in default mount options */
439 g_object_set_data_full (object,
440 "mount-options",
441 udisks_linux_mount_options_get_builtin (),
442 (GDestroyNotify) g_hash_table_destroy);
443
444 /* Load modules if requested but only once providers have started and
445 * have connected on the UDisksModuleManager::modules-activated signal.
446 */
447 if (daemon->force_load_modules ||
448 udisks_config_manager_get_load_preference (daemon->config_manager) == UDISKS_MODULE_LOAD_ONSTARTUP)
449 {
450 /* load all modules */
451 g_idle_add (load_modules_in_idle_cb, daemon);
452 } else {
453 /* crash recovery - load active modules from previous session */
454 g_idle_add (check_modules_state_in_idle_cb, daemon);
455 }
456
457 /* Export the ObjectManager */
458 g_dbus_object_manager_server_set_connection (daemon->object_manager, daemon->connection);
459
460 /* Start cleaning up */
461 udisks_state_start_cleanup (daemon->state);
462 udisks_state_check (daemon->state);
463
464 if (G_OBJECT_CLASS (udisks_daemon_parent_class)->constructed != NULL)
465 G_OBJECT_CLASS (udisks_daemon_parent_class)->constructed (object);
466 }
467
468
469 static void
udisks_daemon_class_init(UDisksDaemonClass * klass)470 udisks_daemon_class_init (UDisksDaemonClass *klass)
471 {
472 GObjectClass *gobject_class;
473
474 gobject_class = G_OBJECT_CLASS (klass);
475 gobject_class->finalize = udisks_daemon_finalize;
476 gobject_class->constructed = udisks_daemon_constructed;
477 gobject_class->set_property = udisks_daemon_set_property;
478 gobject_class->get_property = udisks_daemon_get_property;
479
480 /**
481 * UDisksDaemon:connection:
482 *
483 * The #GDBusConnection the daemon is for.
484 */
485 g_object_class_install_property (gobject_class,
486 PROP_CONNECTION,
487 g_param_spec_object ("connection",
488 "Connection",
489 "The D-Bus connection the daemon is for",
490 G_TYPE_DBUS_CONNECTION,
491 G_PARAM_READABLE |
492 G_PARAM_WRITABLE |
493 G_PARAM_CONSTRUCT_ONLY |
494 G_PARAM_STATIC_STRINGS));
495
496 /**
497 * UDisksDaemon:object-manager:
498 *
499 * The #GDBusObjectManager used by the daemon
500 */
501 g_object_class_install_property (gobject_class,
502 PROP_OBJECT_MANAGER,
503 g_param_spec_object ("object-manager",
504 "Object Manager",
505 "The D-Bus Object Manager server used by the daemon",
506 G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
507 G_PARAM_READABLE |
508 G_PARAM_STATIC_STRINGS));
509
510 /**
511 * UDisksDaemon:mount-monitor:
512 *
513 * The #UDisksMountMonitor used by the daemon
514 */
515 g_object_class_install_property (gobject_class,
516 PROP_MOUNT_MONITOR,
517 g_param_spec_object ("mount-monitor",
518 "Mount Monitor",
519 "The mount monitor",
520 UDISKS_TYPE_MOUNT_MONITOR,
521 G_PARAM_READABLE |
522 G_PARAM_STATIC_STRINGS));
523
524 /**
525 * UDisksDaemon:disable-modules:
526 *
527 * Whether modules should be disabled
528 */
529 g_object_class_install_property (gobject_class,
530 PROP_DISABLE_MODULES,
531 g_param_spec_boolean ("disable-modules",
532 "Disable modules",
533 "Whether modules should be disabled",
534 FALSE,
535 G_PARAM_READABLE |
536 G_PARAM_WRITABLE |
537 G_PARAM_CONSTRUCT_ONLY));
538
539 /**
540 * UDisksDaemon:force-load-modules:
541 *
542 * Whether modules should be activated upon startup
543 */
544 g_object_class_install_property (gobject_class,
545 PROP_FORCE_LOAD_MODULES,
546 g_param_spec_boolean ("force-load-modules",
547 "Force load modules",
548 "Whether modules should be activated upon startup",
549 FALSE,
550 G_PARAM_READABLE |
551 G_PARAM_WRITABLE |
552 G_PARAM_CONSTRUCT_ONLY));
553
554 /**
555 * UDisksDaemon:uninstalled:
556 *
557 * Loads modules from the build directory.
558 */
559 g_object_class_install_property (gobject_class,
560 PROP_UNINSTALLED,
561 g_param_spec_boolean ("uninstalled",
562 "Load modules from the build directory",
563 "Whether the modules should be loaded from the build directory",
564 FALSE,
565 G_PARAM_READABLE |
566 G_PARAM_WRITABLE |
567 G_PARAM_CONSTRUCT_ONLY));
568
569 /**
570 * UDisksDaemon:enable-tcrypt:
571 *
572 * Whether devices should be tested for being TCRYPT encrypted.
573 */
574 g_object_class_install_property (gobject_class,
575 PROP_ENABLE_TCRYPT,
576 g_param_spec_boolean ("enable-tcrypt",
577 "Enable TCRYPT",
578 "Whether devices should be tested for being TCRYPT encrypted",
579 FALSE,
580 G_PARAM_READABLE |
581 G_PARAM_WRITABLE |
582 G_PARAM_CONSTRUCT_ONLY));
583
584 /**
585 * UDisksDaemon:uuid:
586 *
587 * The UUID specific for this daemon instance.
588 */
589 g_object_class_install_property (gobject_class,
590 PROP_UUID,
591 g_param_spec_string ("uuid",
592 "Daemon UUID",
593 "The UUID specific for this daemon instance",
594 NULL,
595 G_PARAM_READABLE |
596 G_PARAM_WRITABLE));
597 }
598
599 /**
600 * udisks_daemon_new:
601 * @connection: A #GDBusConnection.
602 * @disable_modules: Indicates whether modules should never be activated.
603 * @force_load_modules: Activate modules on startup (for debugging purposes).
604 * @uninstalled: Loads modules from the build directory (for debugging purposes).
605 * @enable_tcrypt: Checks whether devices could be TCRYPT encrypted.
606 *
607 * Create a new daemon object for exporting objects on @connection.
608 *
609 * Returns: A #UDisksDaemon object. Free with g_object_unref().
610 */
611 UDisksDaemon *
udisks_daemon_new(GDBusConnection * connection,gboolean disable_modules,gboolean force_load_modules,gboolean uninstalled,gboolean enable_tcrypt)612 udisks_daemon_new (GDBusConnection *connection,
613 gboolean disable_modules,
614 gboolean force_load_modules,
615 gboolean uninstalled,
616 gboolean enable_tcrypt)
617 {
618 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
619 return UDISKS_DAEMON (g_object_new (UDISKS_TYPE_DAEMON,
620 "connection", connection,
621 "disable-modules", disable_modules,
622 "force-load-modules", force_load_modules,
623 "uninstalled", uninstalled,
624 "enable-tcrypt", enable_tcrypt,
625 NULL));
626 }
627
628 /**
629 * udisks_daemon_get_connection:
630 * @daemon: A #UDisksDaemon.
631 *
632 * Gets the D-Bus connection used by @daemon.
633 *
634 * Returns: A #GDBusConnection. Do not free, the object is owned by @daemon.
635 */
636 GDBusConnection *
udisks_daemon_get_connection(UDisksDaemon * daemon)637 udisks_daemon_get_connection (UDisksDaemon *daemon)
638 {
639 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
640 return daemon->connection;
641 }
642
643 /**
644 * udisks_daemon_get_object_manager:
645 * @daemon: A #UDisksDaemon.
646 *
647 * Gets the D-Bus object manager used by @daemon.
648 *
649 * Returns: A #GDBusObjectManagerServer. Do not free, the object is owned by @daemon.
650 */
651 GDBusObjectManagerServer *
udisks_daemon_get_object_manager(UDisksDaemon * daemon)652 udisks_daemon_get_object_manager (UDisksDaemon *daemon)
653 {
654 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
655 return daemon->object_manager;
656 }
657
658 /**
659 * udisks_daemon_get_mount_monitor:
660 * @daemon: A #UDisksDaemon
661 *
662 * Gets the mount monitor used by @daemon.
663 *
664 * Returns: A #UDisksMountMonitor. Do not free, the object is owned by @daemon.
665 */
666 UDisksMountMonitor *
udisks_daemon_get_mount_monitor(UDisksDaemon * daemon)667 udisks_daemon_get_mount_monitor (UDisksDaemon *daemon)
668 {
669 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
670 return daemon->mount_monitor;
671 }
672
673 /**
674 * udisks_daemon_get_crypttab_monitor:
675 * @daemon: A #UDisksDaemon
676 *
677 * Gets the crypttab monitor used by @daemon.
678 *
679 * Returns: A #UDisksCrypttabMonitor. Do not free, the object is owned by @daemon.
680 */
681 UDisksCrypttabMonitor *
udisks_daemon_get_crypttab_monitor(UDisksDaemon * daemon)682 udisks_daemon_get_crypttab_monitor (UDisksDaemon *daemon)
683 {
684 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
685 return daemon->crypttab_monitor;
686 }
687
688 #ifdef HAVE_LIBMOUNT_UTAB
689 /**
690 * udisks_daemon_get_utab_monitor:
691 * @daemon: A #UDisksDaemon
692 *
693 * Gets the utab monitor used by @daemon.
694 *
695 * Returns: A #UDisksUtabMonitor. Do not free, the object is owned by @daemon.
696 */
697 UDisksUtabMonitor *
udisks_daemon_get_utab_monitor(UDisksDaemon * daemon)698 udisks_daemon_get_utab_monitor (UDisksDaemon *daemon)
699 {
700 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
701 return daemon->utab_monitor;
702 }
703 #endif
704
705 /**
706 * udisks_daemon_get_linux_provider:
707 * @daemon: A #UDisksDaemon.
708 *
709 * Gets the Linux Provider, if any.
710 *
711 * Returns: A #UDisksLinuxProvider or %NULL. Do not free, the object is owned by @daemon.
712 */
713 UDisksLinuxProvider *
udisks_daemon_get_linux_provider(UDisksDaemon * daemon)714 udisks_daemon_get_linux_provider (UDisksDaemon *daemon)
715 {
716 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
717 return daemon->linux_provider;
718 }
719
720 /**
721 * udisks_daemon_get_authority:
722 * @daemon: A #UDisksDaemon.
723 *
724 * Gets the PolicyKit authority used by @daemon.
725 *
726 * Returns: A #PolkitAuthority instance or %NULL if the polkit
727 * authority is not available. Do not free, the object is owned by
728 * @daemon.
729 */
730 PolkitAuthority *
udisks_daemon_get_authority(UDisksDaemon * daemon)731 udisks_daemon_get_authority (UDisksDaemon *daemon)
732 {
733 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
734 return daemon->authority;
735 }
736
737 /**
738 * udisks_daemon_get_state:
739 * @daemon: A #UDisksDaemon.
740 *
741 * Gets the state object used by @daemon.
742 *
743 * Returns: A #UDisksState instance. Do not free, the object is owned by @daemon.
744 */
745 UDisksState *
udisks_daemon_get_state(UDisksDaemon * daemon)746 udisks_daemon_get_state (UDisksDaemon *daemon)
747 {
748 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
749 return daemon->state;
750 }
751
752 /* ---------------------------------------------------------------------------------------------------- */
753
754 typedef struct
755 {
756 UDisksDaemon *daemon;
757 UDisksInhibitCookie *inhibit_cookie;
758 } JobData;
759
760 static void
free_job_data(JobData * job_data)761 free_job_data (JobData *job_data)
762 {
763 if (job_data->daemon != NULL)
764 g_object_unref (job_data->daemon);
765 g_free (job_data);
766 }
767
768 static void
on_job_completed(UDisksJob * job,gboolean success,const gchar * message,gpointer user_data)769 on_job_completed (UDisksJob *job,
770 gboolean success,
771 const gchar *message,
772 gpointer user_data)
773 {
774 JobData *job_data = (JobData *) user_data;
775 UDisksDaemon *daemon = UDISKS_DAEMON (job_data->daemon);
776 UDisksObjectSkeleton *object;
777
778 object = UDISKS_OBJECT_SKELETON (g_dbus_interface_get_object (G_DBUS_INTERFACE (job)));
779 g_assert (object != NULL);
780
781 /* Unexport job */
782 g_dbus_object_manager_server_unexport (daemon->object_manager,
783 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
784 g_object_unref (object);
785
786 /* free the allocated job object */
787 g_object_unref (job);
788
789 /* unregister inhibitor from systemd logind */
790 udisks_daemon_util_uninhibit_system_sync (job_data->inhibit_cookie);
791 /* returns the reference we took when connecting to the
792 * UDisksJob::completed signal in udisks_daemon_launch_{spawned,threaded}_job()
793 * below
794 */
795 free_job_data (job_data);
796 }
797
798 /* ---------------------------------------------------------------------------------------------------- */
799
800 static guint job_id = 0;
801
802 /* ---------------------------------------------------------------------------------------------------- */
803
804 static UDisksBaseJob *
common_job(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,gpointer job)805 common_job (UDisksDaemon *daemon,
806 UDisksObject *object,
807 const gchar *job_operation,
808 uid_t job_started_by_uid,
809 gpointer job)
810 {
811 gchar *job_object_path;
812 UDisksObjectSkeleton *job_object;
813 JobData *job_data;
814 gchar *operation_description;
815
816 job_data = g_new0 (JobData, 1);
817 job_data->daemon = g_object_ref (daemon);
818 /* register inhibitor to systemd logind while job is running */
819 operation_description = udisks_client_get_job_description_from_operation (job_operation);
820 job_data->inhibit_cookie = udisks_daemon_util_inhibit_system_sync (operation_description);
821 g_free (operation_description);
822
823 if (object != NULL)
824 udisks_base_job_add_object (UDISKS_BASE_JOB (job), object);
825
826 job_object_path = g_strdup_printf ("/org/freedesktop/UDisks2/jobs/%u", g_atomic_int_add (&job_id, 1));
827 job_object = udisks_object_skeleton_new (job_object_path);
828 udisks_object_skeleton_set_job (job_object, UDISKS_JOB (job));
829 g_free (job_object_path);
830
831 udisks_job_set_cancelable (UDISKS_JOB (job), TRUE);
832 udisks_job_set_operation (UDISKS_JOB (job), job_operation);
833 udisks_job_set_started_by_uid (UDISKS_JOB (job), job_started_by_uid);
834
835 g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (job_object));
836 g_signal_connect_after (job,
837 "completed",
838 G_CALLBACK (on_job_completed),
839 job_data);
840
841 return UDISKS_BASE_JOB (job);
842 }
843
844 /**
845 * udisks_daemon_launch_simple_job:
846 * @daemon: A #UDisksDaemon.
847 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
848 * @job_operation: The operation for the job.
849 * @job_started_by_uid: The user who started the job.
850 * @cancellable: A #GCancellable or %NULL.
851 *
852 * Launches a new simple job.
853 *
854 * The returned object will be exported on the bus until the
855 * #UDisksJob::completed signal is emitted on the object. It is not
856 * valid to use the returned object after this signal fires.
857 *
858 * Returns: A #UDisksSimpleJob object. Do not free, the object
859 * belongs to @manager.
860 */
861 UDisksBaseJob *
udisks_daemon_launch_simple_job(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,GCancellable * cancellable)862 udisks_daemon_launch_simple_job (UDisksDaemon *daemon,
863 UDisksObject *object,
864 const gchar *job_operation,
865 uid_t job_started_by_uid,
866 GCancellable *cancellable)
867 {
868 UDisksSimpleJob *job;
869
870 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
871
872 job = udisks_simple_job_new (daemon, cancellable);
873 return common_job (daemon, object, job_operation, job_started_by_uid, job);
874 }
875
876 /* ---------------------------------------------------------------------------------------------------- */
877
878 /**
879 * udisks_daemon_launch_threaded_job:
880 * @daemon: A #UDisksDaemon.
881 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
882 * @job_operation: The operation for the job.
883 * @job_started_by_uid: The user who started the job.
884 * @job_func: The function to run in another thread.
885 * @user_data: User data to pass to @job_func.
886 * @user_data_free_func: Function to free @user_data with or %NULL.
887 * @cancellable: A #GCancellable or %NULL.
888 *
889 * Launches a new job by running @job_func in a new dedicated thread.
890 *
891 * The job is not started automatically! Use udisks_threaded_job_start() to
892 * start the job after #UDisksThreadedJob::threaded-job-completed or
893 * #UDisksJob::completed signals are connected (to get notified when the job is
894 * done). This is to prevent a race condition with the @job_func finishing
895 * before the signals are connected in which case the signal handlers are never
896 * triggered.
897 *
898 * Long-running jobs should periodically check @cancellable to see if
899 * they have been cancelled.
900 *
901 * The returned object will be exported on the bus until the
902 * #UDisksJob::completed signal is emitted on the object. It is not
903 * valid to use the returned object after this signal fires.
904 *
905 * Returns: A #UDisksThreadedJob object. Do not free, the object
906 * belongs to @manager.
907 */
908 UDisksBaseJob *
udisks_daemon_launch_threaded_job(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,UDisksThreadedJobFunc job_func,gpointer user_data,GDestroyNotify user_data_free_func,GCancellable * cancellable)909 udisks_daemon_launch_threaded_job (UDisksDaemon *daemon,
910 UDisksObject *object,
911 const gchar *job_operation,
912 uid_t job_started_by_uid,
913 UDisksThreadedJobFunc job_func,
914 gpointer user_data,
915 GDestroyNotify user_data_free_func,
916 GCancellable *cancellable)
917 {
918 UDisksThreadedJob *job;
919
920 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
921 g_return_val_if_fail (job_func != NULL, NULL);
922
923 job = udisks_threaded_job_new (job_func,
924 user_data,
925 user_data_free_func,
926 daemon,
927 cancellable);
928 return common_job (daemon, object, job_operation, job_started_by_uid, job);
929 }
930
931 /* ---------------------------------------------------------------------------------------------------- */
932
933 /**
934 * udisks_daemon_launch_spawned_job:
935 * @daemon: A #UDisksDaemon.
936 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
937 * @job_operation: The operation for the job.
938 * @job_started_by_uid: The user who started the job.
939 * @cancellable: A #GCancellable or %NULL.
940 * @run_as_uid: The #uid_t to run the command as.
941 * @run_as_euid: The effective #uid_t to run the command as.
942 * @input_string: A string to write to stdin of the spawned program or %NULL.
943 * @command_line_format: printf()-style format for the command line to spawn.
944 * @...: Arguments for @command_line_format.
945 *
946 * Launches a new job for @command_line_format.
947 *
948 * The job is not started automatically! Use udisks_spawned_job_start() to start
949 * the job after #UDisksSpawnedJob::spawned-job-completed or
950 * #UDisksJob::completed signals are connected (to get notified when the job is
951 * done). This is to prevent a race condition with the spawned process
952 * terminating before the signals are connected in which case the signal
953 * handlers are never triggered.
954 *
955 * The returned object will be exported on the bus until the
956 * #UDisksJob::completed signal is emitted on the object. It is not
957 * valid to use the returned object after this signal fires.
958 *
959 * Returns: A #UDisksSpawnedJob object. Do not free, the object
960 * belongs to @manager.
961 */
962 UDisksBaseJob *
udisks_daemon_launch_spawned_job(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,GCancellable * cancellable,uid_t run_as_uid,uid_t run_as_euid,const gchar * input_string,const gchar * command_line_format,...)963 udisks_daemon_launch_spawned_job (UDisksDaemon *daemon,
964 UDisksObject *object,
965 const gchar *job_operation,
966 uid_t job_started_by_uid,
967 GCancellable *cancellable,
968 uid_t run_as_uid,
969 uid_t run_as_euid,
970 const gchar *input_string,
971 const gchar *command_line_format,
972 ...)
973 {
974 va_list var_args;
975 gchar *command_line;
976 GString *input_string_as_gstring = NULL;
977 UDisksBaseJob *job;
978
979 if (input_string != NULL)
980 input_string_as_gstring = g_string_new (input_string);
981
982 va_start (var_args, command_line_format);
983 command_line = g_strdup_vprintf (command_line_format, var_args);
984 va_end (var_args);
985
986 job = udisks_daemon_launch_spawned_job_gstring (daemon,
987 object,
988 job_operation,
989 job_started_by_uid,
990 cancellable,
991 run_as_uid,
992 run_as_euid,
993 input_string_as_gstring,
994 "%s",
995 command_line);
996
997 udisks_string_wipe_and_free (input_string_as_gstring);
998 g_free (command_line);
999 return job;
1000 }
1001
1002 /**
1003 * udisks_daemon_launch_spawned_job_gstring:
1004 * @daemon: A #UDisksDaemon.
1005 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
1006 * @job_operation: The operation for the job.
1007 * @job_started_by_uid: The user who started the job.
1008 * @cancellable: A #GCancellable or %NULL.
1009 * @run_as_uid: The #uid_t to run the command as.
1010 * @run_as_euid: The effective #uid_t to run the command as.
1011 * @input_string: A string to write to stdin of the spawned program or %NULL.
1012 * @command_line_format: printf()-style format for the command line to spawn.
1013 * @...: Arguments for @command_line_format.
1014 *
1015 * Launches a new job for @command_line_format.
1016 *
1017 * The job is not started automatically! Use udisks_spawned_job_start() to start
1018 * the job after #UDisksSpawnedJob::spawned-job-completed or
1019 * #UDisksJob::completed signals are connected (to get notified when the job is
1020 * done). This is to prevent a race condition with the spawned process
1021 * terminating before the signals are connected in which case the signal
1022 * handlers are never triggered.
1023 *
1024 * The returned object will be exported on the bus until the
1025 * #UDisksJob::completed signal is emitted on the object. It is not
1026 * valid to use the returned object after this signal fires.
1027 *
1028 * This function is the same as udisks_daemon_launch_spawned_job, with
1029 * the only difference that it takes a GString and is therefore able to
1030 * handle binary inputs that contain '\0' bytes.
1031 *
1032 * Returns: A #UDisksSpawnedJob object. Do not free, the object
1033 * belongs to @manager.
1034 */
1035 UDisksBaseJob *
udisks_daemon_launch_spawned_job_gstring(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,GCancellable * cancellable,uid_t run_as_uid,uid_t run_as_euid,GString * input_string,const gchar * command_line_format,...)1036 udisks_daemon_launch_spawned_job_gstring (
1037 UDisksDaemon *daemon,
1038 UDisksObject *object,
1039 const gchar *job_operation,
1040 uid_t job_started_by_uid,
1041 GCancellable *cancellable,
1042 uid_t run_as_uid,
1043 uid_t run_as_euid,
1044 GString *input_string,
1045 const gchar *command_line_format,
1046 ...)
1047 {
1048 va_list var_args;
1049 gchar *command_line;
1050 UDisksSpawnedJob *job;
1051
1052 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
1053 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1054 g_return_val_if_fail (command_line_format != NULL, NULL);
1055
1056 va_start (var_args, command_line_format);
1057 command_line = g_strdup_vprintf (command_line_format, var_args);
1058 va_end (var_args);
1059 job = udisks_spawned_job_new (command_line, input_string, run_as_uid, run_as_euid, daemon, cancellable);
1060 g_free (command_line);
1061
1062 return common_job (daemon, object, job_operation, job_started_by_uid, job);
1063 }
1064
1065 /* ---------------------------------------------------------------------------------------------------- */
1066
1067 typedef struct
1068 {
1069 GMainContext *context;
1070 GMainLoop *loop;
1071 gboolean success;
1072 gint status;
1073 gchar *message;
1074 } SpawnedJobSyncData;
1075
1076 static gboolean
spawned_job_sync_on_spawned_job_completed(UDisksSpawnedJob * job,GError * error,gint status,GString * standard_output,GString * standard_error,gpointer user_data)1077 spawned_job_sync_on_spawned_job_completed (UDisksSpawnedJob *job,
1078 GError *error,
1079 gint status,
1080 GString *standard_output,
1081 GString *standard_error,
1082 gpointer user_data)
1083 {
1084 SpawnedJobSyncData *data = user_data;
1085 data->status = status;
1086 return FALSE; /* let other handlers run */
1087 }
1088
1089 static void
spawned_job_sync_on_completed(UDisksJob * job,gboolean success,const gchar * message,gpointer user_data)1090 spawned_job_sync_on_completed (UDisksJob *job,
1091 gboolean success,
1092 const gchar *message,
1093 gpointer user_data)
1094 {
1095 SpawnedJobSyncData *data = user_data;
1096 data->success = success;
1097 data->message = g_strdup (message);
1098 g_main_loop_quit (data->loop);
1099 }
1100
1101 /**
1102 * udisks_daemon_launch_spawned_job_sync:
1103 * @daemon: A #UDisksDaemon.
1104 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
1105 * @job_operation: The operation for the job.
1106 * @job_started_by_uid: The user who started the job.
1107 * @cancellable: A #GCancellable or %NULL.
1108 * @run_as_uid: The #uid_t to run the command as.
1109 * @run_as_euid: The effective #uid_t to run the command as.
1110 * @input_string: A string to write to stdin of the spawned program or %NULL.
1111 * @out_status: Return location for the @status parameter of the #UDisksSpawnedJob::spawned-job-completed signal.
1112 * @out_message: Return location for the @message parameter of the #UDisksJob::completed signal.
1113 * @command_line_format: printf()-style format for the command line to spawn.
1114 * @...: Arguments for @command_line_format.
1115 *
1116 * Like udisks_daemon_launch_spawned_job() but blocks the calling
1117 * thread until the job completes.
1118 *
1119 * Returns: The @success parameter of the #UDisksJob::completed signal.
1120 */
1121 gboolean
udisks_daemon_launch_spawned_job_sync(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,GCancellable * cancellable,uid_t run_as_uid,uid_t run_as_euid,gint * out_status,gchar ** out_message,const gchar * input_string,const gchar * command_line_format,...)1122 udisks_daemon_launch_spawned_job_sync (UDisksDaemon *daemon,
1123 UDisksObject *object,
1124 const gchar *job_operation,
1125 uid_t job_started_by_uid,
1126 GCancellable *cancellable,
1127 uid_t run_as_uid,
1128 uid_t run_as_euid,
1129 gint *out_status,
1130 gchar **out_message,
1131 const gchar *input_string,
1132 const gchar *command_line_format,
1133 ...)
1134 {
1135 va_list var_args;
1136 gchar *command_line;
1137 GString *input_string_as_gstring = NULL;
1138 gboolean ret;
1139
1140 if (input_string != NULL)
1141 input_string_as_gstring = g_string_new (input_string);
1142
1143 va_start (var_args, command_line_format);
1144 command_line = g_strdup_vprintf (command_line_format, var_args);
1145 va_end (var_args);
1146
1147 ret = udisks_daemon_launch_spawned_job_gstring_sync (daemon,
1148 object,
1149 job_operation,
1150 job_started_by_uid,
1151 cancellable,
1152 run_as_uid,
1153 run_as_euid,
1154 out_status,
1155 out_message,
1156 input_string_as_gstring,
1157 "%s",
1158 command_line);
1159
1160 udisks_string_wipe_and_free (input_string_as_gstring);
1161 g_free (command_line);
1162 return ret;
1163 }
1164
1165 /**
1166 * udisks_daemon_launch_spawned_job_gstring_sync:
1167 * @daemon: A #UDisksDaemon.
1168 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
1169 * @job_operation: The operation for the job.
1170 * @job_started_by_uid: The user who started the job.
1171 * @cancellable: A #GCancellable or %NULL.
1172 * @run_as_uid: The #uid_t to run the command as.
1173 * @run_as_euid: The effective #uid_t to run the command as.
1174 * @input_string: A string to write to stdin of the spawned program or %NULL.
1175 * @out_status: Return location for the @status parameter of the #UDisksSpawnedJob::spawned-job-completed signal.
1176 * @out_message: Return location for the @message parameter of the #UDisksJob::completed signal.
1177 * @command_line_format: printf()-style format for the command line to spawn.
1178 * @...: Arguments for @command_line_format.
1179 *
1180 * Like udisks_daemon_launch_spawned_job() but blocks the calling
1181 * thread until the job completes.
1182 *
1183 * This function is the same as udisks_daemon_launch_spawned_job_sync, with
1184 * the only difference that it takes a GString and is therefore able to
1185 * handle binary inputs that contain '\0' bytes.
1186 *
1187 * Returns: The @success parameter of the #UDisksJob::completed signal.
1188 */
1189 gboolean
udisks_daemon_launch_spawned_job_gstring_sync(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,GCancellable * cancellable,uid_t run_as_uid,uid_t run_as_euid,gint * out_status,gchar ** out_message,GString * input_string,const gchar * command_line_format,...)1190 udisks_daemon_launch_spawned_job_gstring_sync (UDisksDaemon *daemon,
1191 UDisksObject *object,
1192 const gchar *job_operation,
1193 uid_t job_started_by_uid,
1194 GCancellable *cancellable,
1195 uid_t run_as_uid,
1196 uid_t run_as_euid,
1197 gint *out_status,
1198 gchar **out_message,
1199 GString *input_string,
1200 const gchar *command_line_format,
1201 ...)
1202 {
1203 va_list var_args;
1204 gchar *command_line;
1205 UDisksBaseJob *job;
1206 SpawnedJobSyncData data;
1207
1208 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1209 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1210 g_return_val_if_fail (command_line_format != NULL, FALSE);
1211
1212 data.context = g_main_context_new ();
1213 g_main_context_push_thread_default (data.context);
1214 data.loop = g_main_loop_new (data.context, FALSE);
1215 data.success = FALSE;
1216 data.status = 0;
1217 data.message = NULL;
1218
1219 va_start (var_args, command_line_format);
1220 command_line = g_strdup_vprintf (command_line_format, var_args);
1221 va_end (var_args);
1222 job = udisks_daemon_launch_spawned_job_gstring (daemon,
1223 object,
1224 job_operation,
1225 job_started_by_uid,
1226 cancellable,
1227 run_as_uid,
1228 run_as_euid,
1229 input_string,
1230 "%s",
1231 command_line);
1232 g_signal_connect (job,
1233 "spawned-job-completed",
1234 G_CALLBACK (spawned_job_sync_on_spawned_job_completed),
1235 &data);
1236 g_signal_connect_after (job,
1237 "completed",
1238 G_CALLBACK (spawned_job_sync_on_completed),
1239 &data);
1240
1241 udisks_spawned_job_start (UDISKS_SPAWNED_JOB (job));
1242 g_main_loop_run (data.loop);
1243
1244 if (out_status != NULL)
1245 *out_status = data.status;
1246
1247 if (out_message != NULL)
1248 *out_message = data.message;
1249 else
1250 g_free (data.message);
1251
1252 g_free (command_line);
1253 g_main_loop_unref (data.loop);
1254 g_main_context_pop_thread_default (data.context);
1255 g_main_context_unref (data.context);
1256
1257 /* note: the job object is freed in the ::completed handler */
1258
1259 return data.success;
1260 }
1261
1262 /* ---------------------------------------------------------------------------------------------------- */
1263
1264 static __thread UDisksJob *thread_job = NULL;
1265
1266 static void
bd_thread_progress_callback(guint64 task_id,BDUtilsProgStatus status,guint8 completion,gchar * msg)1267 bd_thread_progress_callback (guint64 task_id,
1268 BDUtilsProgStatus status,
1269 guint8 completion,
1270 gchar *msg)
1271 {
1272 if (thread_job != NULL && msg == NULL)
1273 {
1274 if (!udisks_job_get_progress_valid (UDISKS_JOB (thread_job)))
1275 {
1276 udisks_job_set_progress_valid (UDISKS_JOB (thread_job), TRUE);
1277 }
1278
1279 udisks_job_set_progress (UDISKS_JOB (thread_job), completion / 100.0);
1280 }
1281 }
1282
1283 void
udisks_bd_thread_set_progress_for_job(UDisksJob * job)1284 udisks_bd_thread_set_progress_for_job (UDisksJob *job)
1285 {
1286 thread_job = job;
1287 bd_utils_init_prog_reporting_thread (bd_thread_progress_callback, NULL);
1288 }
1289
1290 void
udisks_bd_thread_disable_progress(void)1291 udisks_bd_thread_disable_progress (void)
1292 {
1293 thread_job = NULL;
1294 bd_utils_init_prog_reporting_thread (NULL, NULL);
1295 }
1296
1297 /* ---------------------------------------------------------------------------------------------------- */
1298
1299 /**
1300 * udisks_daemon_launch_threaded_job_sync:
1301 * @daemon: A #UDisksDaemon.
1302 * @object: (allow-none): A #UDisksObject to add to the job or %NULL.
1303 * @job_operation: The operation for the job.
1304 * @job_started_by_uid: The user who started the job.
1305 * @job_func: The function to run in another thread.
1306 * @user_data: User data to pass to @job_func.
1307 * @user_data_free_func: Function to free @user_data with or %NULL.
1308 * @cancellable: A #GCancellable or %NULL.
1309 * @error: The #GError set by the #UDisksThreadedJobFunc.
1310 *
1311 * Like udisks_daemon_launch_threaded_job() but blocks the calling
1312 * thread until the job completes.
1313 *
1314 * Returns: The @success parameter of the #UDisksJob::completed signal.
1315 */
1316 gboolean
udisks_daemon_launch_threaded_job_sync(UDisksDaemon * daemon,UDisksObject * object,const gchar * job_operation,uid_t job_started_by_uid,UDisksThreadedJobFunc job_func,gpointer user_data,GDestroyNotify user_data_free_func,GCancellable * cancellable,GError ** error)1317 udisks_daemon_launch_threaded_job_sync (UDisksDaemon *daemon,
1318 UDisksObject *object,
1319 const gchar *job_operation,
1320 uid_t job_started_by_uid,
1321 UDisksThreadedJobFunc job_func,
1322 gpointer user_data,
1323 GDestroyNotify user_data_free_func,
1324 GCancellable *cancellable,
1325 GError **error)
1326 {
1327 UDisksBaseJob *job;
1328 gboolean job_result;
1329
1330 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1331 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1332
1333 job = udisks_daemon_launch_threaded_job (daemon,
1334 object,
1335 job_operation,
1336 job_started_by_uid,
1337 job_func,
1338 user_data,
1339 user_data_free_func,
1340 cancellable);
1341
1342 /* TODO: There might not be much difference between calling the job_func() right away
1343 * instead of having it enclosed in a GTask since we're blocking anyway.
1344 * Deeper investigation of differences required. */
1345 job_result = udisks_threaded_job_run_sync (UDISKS_THREADED_JOB (job), error);
1346
1347 /* note: the job object is freed in the ::completed handler */
1348 return job_result;
1349 }
1350
1351 /* ---------------------------------------------------------------------------------------------------- */
1352
1353 typedef struct {
1354 GMainContext *context;
1355 GMainLoop *loop;
1356 gboolean timed_out;
1357 } WaitData;
1358
1359 static gboolean
wait_on_timed_out(gpointer user_data)1360 wait_on_timed_out (gpointer user_data)
1361 {
1362 WaitData *data = user_data;
1363 data->timed_out = TRUE;
1364 g_main_loop_quit (data->loop);
1365 return FALSE; /* remove the source */
1366 }
1367
1368 static gboolean
wait_on_recheck(gpointer user_data)1369 wait_on_recheck (gpointer user_data)
1370 {
1371 WaitData *data = user_data;
1372 g_main_loop_quit (data->loop);
1373 return FALSE; /* remove the source */
1374 }
1375
wait_for_objects(UDisksDaemon * daemon,UDisksDaemonWaitFuncGeneric wait_func,gpointer user_data,GDestroyNotify user_data_free_func,guint timeout_seconds,gboolean to_disappear,GError ** error)1376 static gpointer wait_for_objects (UDisksDaemon *daemon,
1377 UDisksDaemonWaitFuncGeneric wait_func,
1378 gpointer user_data,
1379 GDestroyNotify user_data_free_func,
1380 guint timeout_seconds,
1381 gboolean to_disappear,
1382 GError **error)
1383 {
1384 gpointer ret;
1385 WaitData data;
1386
1387 /* TODO: support GCancellable */
1388
1389 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
1390 g_return_val_if_fail (wait_func != NULL, NULL);
1391
1392 ret = NULL;
1393
1394 memset (&data, '\0', sizeof (data));
1395 data.context = NULL;
1396 data.loop = NULL;
1397
1398 g_object_ref (daemon);
1399
1400 again:
1401 ret = wait_func (daemon, user_data);
1402
1403 if ((!to_disappear && ret == NULL && timeout_seconds > 0) ||
1404 (to_disappear && ret != NULL && timeout_seconds > 0))
1405 {
1406 GSource *source;
1407
1408 /* sit and wait for up to @timeout_seconds if the object isn't there already */
1409 if (data.context == NULL)
1410 {
1411 /* TODO: this will deadlock if we are calling from the main thread... */
1412 data.context = g_main_context_new ();
1413 data.loop = g_main_loop_new (data.context, FALSE);
1414
1415 source = g_timeout_source_new_seconds (timeout_seconds);
1416 g_source_set_priority (source, G_PRIORITY_DEFAULT);
1417 g_source_set_callback (source, wait_on_timed_out, &data, NULL);
1418 g_source_attach (source, data.context);
1419 g_source_unref (source);
1420 }
1421
1422 /* TODO: do something a bit more elegant than checking every 250ms ... it's
1423 * probably going to involve having each UDisksProvider emit a "changed"
1424 * signal when it's time to recheck... for now this works.
1425 */
1426 source = g_timeout_source_new (250);
1427 g_source_set_priority (source, G_PRIORITY_DEFAULT);
1428 g_source_set_callback (source, wait_on_recheck, &data, NULL);
1429 g_source_attach (source, data.context);
1430 g_source_unref (source);
1431
1432 g_main_loop_run (data.loop);
1433
1434 if (data.timed_out)
1435 {
1436 if (to_disappear)
1437 g_set_error (error,
1438 UDISKS_ERROR, UDISKS_ERROR_FAILED,
1439 "Timed out waiting");
1440 else
1441 g_set_error (error,
1442 UDISKS_ERROR, UDISKS_ERROR_FAILED,
1443 "Timed out waiting for object");
1444 }
1445 else
1446 {
1447 if (to_disappear)
1448 g_object_unref (G_OBJECT (ret));
1449 goto again;
1450 }
1451 }
1452
1453 if (user_data_free_func != NULL)
1454 user_data_free_func (user_data);
1455
1456 g_object_unref (daemon);
1457
1458 if (data.loop != NULL)
1459 g_main_loop_unref (data.loop);
1460 if (data.context != NULL)
1461 g_main_context_unref (data.context);
1462
1463 return ret;
1464 }
1465
1466
1467 /**
1468 * udisks_daemon_wait_for_object_sync:
1469 * @daemon: A #UDisksDaemon.
1470 * @wait_func: Function to check for desired object.
1471 * @user_data: User data to pass to @wait_func.
1472 * @user_data_free_func: (allow-none): Function to free @user_data or %NULL.
1473 * @timeout_seconds: Maximum time to wait for the object (in seconds) or 0 to never wait.
1474 * @error: (allow-none): Return location for error or %NULL.
1475 *
1476 * Blocks the calling thread until an object picked by @wait_func is
1477 * available or until @timeout_seconds has passed (in which case the
1478 * function fails with %UDISKS_ERROR_TIMED_OUT).
1479 *
1480 * Note that @wait_func will be called from time to time - for example
1481 * if there is a device event.
1482 *
1483 * Returns: (transfer full): The object picked by @wait_func or %NULL if @error is set.
1484 */
1485 UDisksObject *
udisks_daemon_wait_for_object_sync(UDisksDaemon * daemon,UDisksDaemonWaitFuncObject wait_func,gpointer user_data,GDestroyNotify user_data_free_func,guint timeout_seconds,GError ** error)1486 udisks_daemon_wait_for_object_sync (UDisksDaemon *daemon,
1487 UDisksDaemonWaitFuncObject wait_func,
1488 gpointer user_data,
1489 GDestroyNotify user_data_free_func,
1490 guint timeout_seconds,
1491 GError **error)
1492 {
1493 return (UDisksObject *) wait_for_objects (daemon,
1494 (UDisksDaemonWaitFuncGeneric) wait_func,
1495 user_data,
1496 user_data_free_func,
1497 timeout_seconds,
1498 FALSE, /* to_disappear */
1499 error);
1500 }
1501
1502 /**
1503 * udisks_daemon_wait_for_objects_sync:
1504 * @daemon: A #UDisksDaemon.
1505 * @wait_func: Function to check for desired object.
1506 * @user_data: User data to pass to @wait_func.
1507 * @user_data_free_func: (allow-none): Function to free @user_data or %NULL.
1508 * @timeout_seconds: Maximum time to wait for the object (in seconds) or 0 to never wait.
1509 * @error: (allow-none): Return location for error or %NULL.
1510 *
1511 * Blocks the calling thread until one or more objects picked by @wait_func
1512 * is/are available or until @timeout_seconds has passed (in which case the
1513 * function fails with %UDISKS_ERROR_TIMED_OUT).
1514 *
1515 * Note that @wait_func will be called from time to time - for example
1516 * if there is a device event.
1517 *
1518 * Returns: (transfer full): The objects picked by @wait_func or %NULL if @error is set.
1519 */
1520 UDisksObject **
udisks_daemon_wait_for_objects_sync(UDisksDaemon * daemon,UDisksDaemonWaitFuncObjects wait_func,gpointer user_data,GDestroyNotify user_data_free_func,guint timeout_seconds,GError ** error)1521 udisks_daemon_wait_for_objects_sync (UDisksDaemon *daemon,
1522 UDisksDaemonWaitFuncObjects wait_func,
1523 gpointer user_data,
1524 GDestroyNotify user_data_free_func,
1525 guint timeout_seconds,
1526 GError **error)
1527 {
1528 return (UDisksObject **) wait_for_objects (daemon,
1529 (UDisksDaemonWaitFuncGeneric) wait_func,
1530 user_data,
1531 user_data_free_func,
1532 timeout_seconds,
1533 FALSE, /* to_disappear */
1534 error);
1535 }
1536
1537
1538 /**
1539 * udisks_daemon_wait_for_object_to_disappear_sync:
1540 * @daemon: A #UDisksDaemon.
1541 * @wait_func: Function to check for desired object.
1542 * @user_data: User data to pass to @wait_func.
1543 * @user_data_free_func: (allow-none): Function to free @user_data or %NULL.
1544 * @timeout_seconds: Maximum time to wait for the object to disappear (in seconds) or 0 to never wait.
1545 * @error: (allow-none): Return location for error or %NULL.
1546 *
1547 * Blocks the calling thread until an object picked by @wait_func disappears or
1548 * until @timeout_seconds has passed (in which case the function fails with
1549 * %UDISKS_ERROR_TIMED_OUT).
1550 *
1551 * Note that @wait_func will be called from time to time - for example
1552 * if there is a device event. For consistency @wait_func is supposed
1553 * to return full reference to an existing object; udisks_daemon_wait_for_object_to_disappear_sync()
1554 * will take care of dropping the reference after each iteration.
1555 *
1556 * Returns: (transfer full): Whether the object picked by @wait_func disappeared or not (@error is set).
1557 */
1558 gboolean
udisks_daemon_wait_for_object_to_disappear_sync(UDisksDaemon * daemon,UDisksDaemonWaitFuncObject wait_func,gpointer user_data,GDestroyNotify user_data_free_func,guint timeout_seconds,GError ** error)1559 udisks_daemon_wait_for_object_to_disappear_sync (UDisksDaemon *daemon,
1560 UDisksDaemonWaitFuncObject wait_func,
1561 gpointer user_data,
1562 GDestroyNotify user_data_free_func,
1563 guint timeout_seconds,
1564 GError **error)
1565 {
1566 UDisksObject *object;
1567
1568 object = (UDisksObject *) wait_for_objects (daemon,
1569 (UDisksDaemonWaitFuncGeneric) wait_func,
1570 user_data,
1571 user_data_free_func,
1572 timeout_seconds,
1573 TRUE, /* to_disappear */
1574 error);
1575 if (object != NULL)
1576 g_object_unref (object);
1577
1578 return NULL == object;
1579 }
1580
1581
1582 /* ---------------------------------------------------------------------------------------------------- */
1583
1584 /**
1585 * udisks_daemon_find_block:
1586 * @daemon: A #UDisksDaemon.
1587 * @block_device_number: A #dev_t with the device number to find.
1588 *
1589 * Finds a block device with the number given by @block_device_number.
1590 *
1591 * Returns: (transfer full): A #UDisksObject or %NULL if not found. Free with g_object_unref().
1592 */
1593 UDisksObject *
udisks_daemon_find_block(UDisksDaemon * daemon,dev_t block_device_number)1594 udisks_daemon_find_block (UDisksDaemon *daemon,
1595 dev_t block_device_number)
1596 {
1597 UDisksObject *ret = NULL;
1598 GList *objects, *l;
1599
1600 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager));
1601 for (l = objects; l != NULL; l = l->next)
1602 {
1603 UDisksObject *object = UDISKS_OBJECT (l->data);
1604 UDisksBlock *block;
1605
1606 block = udisks_object_peek_block (object);
1607 if (block == NULL)
1608 continue;
1609
1610 if (udisks_block_get_device_number (block) == block_device_number)
1611 {
1612 ret = g_object_ref (object);
1613 goto out;
1614 }
1615 }
1616 out:
1617 g_list_free_full (objects, g_object_unref);
1618 return ret;
1619 }
1620
1621 /* ---------------------------------------------------------------------------------------------------- */
1622
1623 /**
1624 * udisks_daemon_find_block_by_device_file:
1625 * @daemon: A #UDisksDaemon.
1626 * @device_file: A device file.
1627 *
1628 * Finds a block device with device file given by @device_file.
1629 *
1630 * Returns: (transfer full): A #UDisksObject or %NULL if not found. Free with g_object_unref().
1631 */
1632 UDisksObject *
udisks_daemon_find_block_by_device_file(UDisksDaemon * daemon,const gchar * device_file)1633 udisks_daemon_find_block_by_device_file (UDisksDaemon *daemon,
1634 const gchar *device_file)
1635 {
1636 UDisksObject *ret = NULL;
1637 GList *objects, *l;
1638
1639 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager));
1640 for (l = objects; l != NULL; l = l->next)
1641 {
1642 UDisksObject *object = UDISKS_OBJECT (l->data);
1643 UDisksBlock *block;
1644
1645 block = udisks_object_peek_block (object);
1646 if (block == NULL)
1647 continue;
1648
1649 if (g_strcmp0 (udisks_block_get_device (block), device_file) == 0)
1650 {
1651 ret = g_object_ref (object);
1652 goto out;
1653 }
1654 }
1655 out:
1656 g_list_free_full (objects, g_object_unref);
1657 return ret;
1658 }
1659
1660 /* ---------------------------------------------------------------------------------------------------- */
1661
1662 /**
1663 * udisks_daemon_find_block_by_sysfs_path:
1664 * @daemon: A #UDisksDaemon.
1665 * @sysfs_path: A sysfs path.
1666 *
1667 * Finds a block device with a sysfs path given by @sysfs_path.
1668 *
1669 * Returns: (transfer full): A #UDisksObject or %NULL if not found. Free with g_object_unref().
1670 */
1671 UDisksObject *
udisks_daemon_find_block_by_sysfs_path(UDisksDaemon * daemon,const gchar * sysfs_path)1672 udisks_daemon_find_block_by_sysfs_path (UDisksDaemon *daemon,
1673 const gchar *sysfs_path)
1674 {
1675 UDisksObject *ret = NULL;
1676 GList *objects, *l;
1677
1678 objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager));
1679 for (l = objects; l != NULL; l = l->next)
1680 {
1681 UDisksObject *object = UDISKS_OBJECT (l->data);
1682 UDisksLinuxDevice *device;
1683
1684 if (!UDISKS_IS_LINUX_BLOCK_OBJECT (object))
1685 continue;
1686
1687 device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (object));
1688 if (device == NULL)
1689 continue;
1690
1691 if (g_strcmp0 (g_udev_device_get_sysfs_path (device->udev_device), sysfs_path) == 0)
1692 {
1693 g_object_unref (device);
1694 ret = g_object_ref (object);
1695 goto out;
1696 }
1697 g_object_unref (device);
1698 }
1699 out:
1700 g_list_free_full (objects, g_object_unref);
1701 return ret;
1702 }
1703
1704 /* ---------------------------------------------------------------------------------------------------- */
1705
1706 /**
1707 * udisks_daemon_find_object:
1708 * @daemon: A #UDisksDaemon.
1709 * @object_path: A #dev_t with the device number to find.
1710 *
1711 * Finds an exported object with the object path given by @object_path.
1712 *
1713 * Returns: (transfer full): A #UDisksObject or %NULL if not found. Free with g_object_unref().
1714 */
1715 UDisksObject *
udisks_daemon_find_object(UDisksDaemon * daemon,const gchar * object_path)1716 udisks_daemon_find_object (UDisksDaemon *daemon,
1717 const gchar *object_path)
1718 {
1719 return (UDisksObject *) g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (daemon->object_manager),
1720 object_path);
1721 }
1722
1723 /**
1724 * udisks_daemon_get_objects:
1725 * @daemon: A #UDisksDaemon.
1726 *
1727 * Gets all D-Bus objects exported by @daemon.
1728 *
1729 * Returns: (transfer full) (element-type UDisksObject): A list of #UDisksObject instances. The returned list should be freed with g_list_free() after each element has been freed with g_object_unref().
1730 */
1731 GList *
udisks_daemon_get_objects(UDisksDaemon * daemon)1732 udisks_daemon_get_objects (UDisksDaemon *daemon)
1733 {
1734 return g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager));
1735 }
1736
1737 /**
1738 * udisks_daemon_get_module_manager:
1739 * @daemon: A #UDisksDaemon.
1740 *
1741 * Gets the module manager used by @daemon.
1742 *
1743 * Returns: A #UDisksModuleManager. Do not free, the object is owned by @daemon.
1744 */
1745 UDisksModuleManager *
udisks_daemon_get_module_manager(UDisksDaemon * daemon)1746 udisks_daemon_get_module_manager (UDisksDaemon *daemon)
1747 {
1748 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
1749 return daemon->module_manager;
1750 }
1751
1752 /**
1753 * udisks_daemon_get_config_manager:
1754 * @daemon: A #UDisksDaemon.
1755 *
1756 * Gets the config manager used by @daemon.
1757 *
1758 * Returns: A #UDisksConfigManager. Do not free, the object is owned by @daemon.
1759 */
1760 UDisksConfigManager *
udisks_daemon_get_config_manager(UDisksDaemon * daemon)1761 udisks_daemon_get_config_manager (UDisksDaemon *daemon)
1762 {
1763 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
1764 return daemon->config_manager;
1765 }
1766
1767 /**
1768 * udisks_daemon_get_disable_modules:
1769 * @daemon: A #UDisksDaemon.
1770 *
1771 * Gets @daemon setting whether modules should never be loaded.
1772 *
1773 * Returns: %TRUE if --disable-modules commandline switch has been specified.
1774 */
1775 gboolean
udisks_daemon_get_disable_modules(UDisksDaemon * daemon)1776 udisks_daemon_get_disable_modules (UDisksDaemon*daemon)
1777 {
1778 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1779 return daemon->disable_modules;
1780 }
1781
1782 /**
1783 * udisks_daemon_get_force_load_modules:
1784 * @daemon: A #UDisksDaemon.
1785 *
1786 * Gets @daemon setting whether modules should be activated upon start.
1787 *
1788 * Returns: %TRUE if --force-load-modules commandline switch has been specified.
1789 */
1790 gboolean
udisks_daemon_get_force_load_modules(UDisksDaemon * daemon)1791 udisks_daemon_get_force_load_modules (UDisksDaemon *daemon)
1792 {
1793 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1794 return daemon->force_load_modules;
1795 }
1796
1797 /**
1798 * udisks_daemon_get_uninstalled:
1799 * @daemon: A #UDisksDaemon.
1800 *
1801 * Gets @daemon setting whether the modules should be loaded from the build
1802 * directory.
1803 *
1804 * Returns: %TRUE if --uninstalled commandline switch has been specified.
1805 */
1806 gboolean
udisks_daemon_get_uninstalled(UDisksDaemon * daemon)1807 udisks_daemon_get_uninstalled (UDisksDaemon *daemon)
1808 {
1809 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1810 return daemon->uninstalled;
1811 }
1812
1813 /**
1814 * udisks_daemon_get_enable_tcrypt:
1815 * @daemon: A #UDisksDaemon.
1816 *
1817 * Gets @daemon setting whether devices should be tested for being TCRYPT
1818 * encrypted.
1819 *
1820 * Returns: %TRUE if "/etc/udisks2/tcrypt.conf" was an existing file during
1821 * daemon startup.
1822 */
1823 gboolean
udisks_daemon_get_enable_tcrypt(UDisksDaemon * daemon)1824 udisks_daemon_get_enable_tcrypt (UDisksDaemon *daemon)
1825 {
1826 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
1827 return daemon->enable_tcrypt;
1828 }
1829
1830 /**
1831 * udisks_daemon_get_uuid:
1832 * @daemon: A #UDisksDaemon.
1833 *
1834 * Gets the UUID string specific to this @daemon instance.
1835 *
1836 * Returns: the UUID string. Do not free, the string is owned by @daemon.
1837 */
1838 const gchar *
udisks_daemon_get_uuid(UDisksDaemon * daemon)1839 udisks_daemon_get_uuid (UDisksDaemon *daemon)
1840 {
1841 g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
1842 return daemon->uuid;
1843 }
1844
1845 /* ---------------------------------------------------------------------------------------------------- */
1846
1847 /**
1848 * udisks_daemon_get_parent_for_tracking:
1849 * @daemon: A #UDisksDaemon.
1850 * @path: object path of a child to find parent of
1851 * @uuid: a pointer to return parent UUID string
1852 *
1853 * Finds parent block device and returns its object path and UUID.
1854 * If the return value is %NULL, the value of @uuid has not been changed.
1855 *
1856 * Returns: (transfer full): object path of the parent device. Free with g_free().
1857 */
1858 gchar *
udisks_daemon_get_parent_for_tracking(UDisksDaemon * daemon,const gchar * path,gchar ** uuid)1859 udisks_daemon_get_parent_for_tracking (UDisksDaemon *daemon,
1860 const gchar *path,
1861 gchar **uuid)
1862 {
1863 const gchar *parent_path = NULL;
1864 const gchar *parent_uuid = NULL;
1865
1866 UDisksObject *object = NULL;
1867 UDisksObject *crypto_object = NULL;
1868 UDisksObject *mdraid_object = NULL;
1869 UDisksObject *table_object = NULL;
1870
1871 UDisksBlock *block;
1872 UDisksBlock *crypto_block;
1873 UDisksMDRaid *mdraid;
1874 UDisksPartition *partition;
1875 UDisksBlock *table_block;
1876
1877 GList *modules;
1878 GList *l;
1879 gchar *path_ret = NULL;
1880
1881 object = udisks_daemon_find_object (daemon, path);
1882 if (object == NULL)
1883 goto out;
1884
1885 block = udisks_object_peek_block (object);
1886 if (block)
1887 {
1888 crypto_object = udisks_daemon_find_object (daemon, udisks_block_get_crypto_backing_device (block));
1889 if (crypto_object)
1890 {
1891 crypto_block = udisks_object_peek_block (crypto_object);
1892 if (crypto_block)
1893 {
1894 parent_uuid = udisks_block_get_id_uuid (crypto_block);
1895 parent_path = udisks_block_get_crypto_backing_device (block);
1896 goto out;
1897 }
1898 }
1899
1900 mdraid_object = udisks_daemon_find_object (daemon, udisks_block_get_mdraid (block));
1901 if (mdraid_object)
1902 {
1903 mdraid = udisks_object_peek_mdraid (mdraid_object);
1904 if (mdraid)
1905 {
1906 parent_uuid = udisks_mdraid_get_uuid (mdraid);
1907 parent_path = udisks_block_get_mdraid (block);
1908 goto out;
1909 }
1910 }
1911
1912 partition = udisks_object_peek_partition (object);
1913 if (partition)
1914 {
1915 table_object = udisks_daemon_find_object (daemon, udisks_partition_get_table (partition));
1916 if (table_object)
1917 {
1918 table_block = udisks_object_peek_block (table_object);
1919 if (table_block)
1920 {
1921 /* We don't want to track partition tables because
1922 they can't be 'closed' in a way that their
1923 children temporarily invisible.
1924 */
1925 parent_uuid = NULL;
1926 parent_path = udisks_partition_get_table (partition);
1927 goto out;
1928 }
1929 }
1930 }
1931 }
1932
1933 out:
1934 g_clear_object (&object);
1935 g_clear_object (&crypto_object);
1936 g_clear_object (&mdraid_object);
1937 g_clear_object (&table_object);
1938
1939 if (parent_path)
1940 {
1941 if (uuid)
1942 *uuid = g_strdup (parent_uuid);
1943 return g_strdup (parent_path);
1944 }
1945
1946 modules = udisks_module_manager_get_modules (daemon->module_manager);
1947 for (l = modules; l != NULL; l = l->next)
1948 {
1949 UDisksModule *module = l->data;
1950
1951 path_ret = udisks_module_track_parent (module, path, uuid);
1952 if (path_ret)
1953 break;
1954 }
1955 g_list_free_full (modules, g_object_unref);
1956
1957 if (path_ret)
1958 return path_ret;
1959
1960 return NULL;
1961 }
1962
1963 /* ---------------------------------------------------------------------------------------------------- */
1964