1 | /* |
2 | * Copyright 2015 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Author: Matthias Clasen <mclasen@redhat.com> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include <gio/gio.h> |
23 | #include <gi18n.h> |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #ifdef HAVE_TERMIOS_H |
27 | #include <termios.h> |
28 | #endif |
29 | |
30 | #include "gio-tool.h" |
31 | |
32 | #define STDIN_FILENO 0 |
33 | |
34 | typedef enum { |
35 | MOUNT_OP_NONE, |
36 | MOUNT_OP_ASKED, |
37 | MOUNT_OP_ABORTED |
38 | } MountOpState; |
39 | |
40 | static int outstanding_mounts = 0; |
41 | static GMainLoop *main_loop; |
42 | static GVolumeMonitor *volume_monitor; |
43 | |
44 | static gboolean mount_mountable = FALSE; |
45 | static gboolean mount_unmount = FALSE; |
46 | static gboolean mount_eject = FALSE; |
47 | static gboolean force = FALSE; |
48 | static gboolean anonymous = FALSE; |
49 | static gboolean mount_list = FALSE; |
50 | static gboolean = FALSE; |
51 | static gboolean mount_monitor = FALSE; |
52 | static gboolean tcrypt_hidden = FALSE; |
53 | static gboolean tcrypt_system = FALSE; |
54 | static guint tcrypt_pim = 0; |
55 | static const char *unmount_scheme = NULL; |
56 | static const char *mount_id = NULL; |
57 | static const char *stop_device_file = NULL; |
58 | static gboolean success = TRUE; |
59 | |
60 | |
61 | static const GOptionEntry entries[] = |
62 | { |
63 | { "mountable" , 'm', 0, G_OPTION_ARG_NONE, &mount_mountable, N_("Mount as mountable" ), NULL }, |
64 | { "device" , 'd', 0, G_OPTION_ARG_STRING, &mount_id, N_("Mount volume with device file, or other identifier" ), N_("ID" ) }, |
65 | { "unmount" , 'u', 0, G_OPTION_ARG_NONE, &mount_unmount, N_("Unmount" ), NULL}, |
66 | { "eject" , 'e', 0, G_OPTION_ARG_NONE, &mount_eject, N_("Eject" ), NULL}, |
67 | { "stop" , 't', 0, G_OPTION_ARG_STRING, &stop_device_file, N_("Stop drive with device file" ), N_("DEVICE" ) }, |
68 | { "unmount-scheme" , 's', 0, G_OPTION_ARG_STRING, &unmount_scheme, N_("Unmount all mounts with the given scheme" ), N_("SCHEME" ) }, |
69 | { "force" , 'f', 0, G_OPTION_ARG_NONE, &force, N_("Ignore outstanding file operations when unmounting or ejecting" ), NULL }, |
70 | { "anonymous" , 'a', 0, G_OPTION_ARG_NONE, &anonymous, N_("Use an anonymous user when authenticating" ), NULL }, |
71 | /* Translator: List here is a verb as in 'List all mounts' */ |
72 | { "list" , 'l', 0, G_OPTION_ARG_NONE, &mount_list, N_("List" ), NULL}, |
73 | { "monitor" , 'o', 0, G_OPTION_ARG_NONE, &mount_monitor, N_("Monitor events" ), NULL}, |
74 | { "detail" , 'i', 0, G_OPTION_ARG_NONE, &extra_detail, N_("Show extra information" ), NULL}, |
75 | { "tcrypt-pim" , 0, 0, G_OPTION_ARG_INT, &tcrypt_pim, N_("The numeric PIM when unlocking a VeraCrypt volume" ), N_("PIM" )}, |
76 | { "tcrypt-hidden" , 0, 0, G_OPTION_ARG_NONE, &tcrypt_hidden, N_("Mount a TCRYPT hidden volume" ), NULL}, |
77 | { "tcrypt-system" , 0, 0, G_OPTION_ARG_NONE, &tcrypt_system, N_("Mount a TCRYPT system volume" ), NULL}, |
78 | { NULL } |
79 | }; |
80 | |
81 | static char * |
82 | prompt_for (const char *prompt, const char *default_value, gboolean echo) |
83 | { |
84 | #ifdef HAVE_TERMIOS_H |
85 | struct termios term_attr; |
86 | int old_flags; |
87 | gboolean restore_flags; |
88 | #endif |
89 | char data[256]; |
90 | int len; |
91 | |
92 | if (default_value && *default_value != 0) |
93 | g_print (format: "%s [%s]: " , prompt, default_value); |
94 | else |
95 | g_print (format: "%s: " , prompt); |
96 | |
97 | data[0] = 0; |
98 | |
99 | #ifdef HAVE_TERMIOS_H |
100 | restore_flags = FALSE; |
101 | if (!echo && tcgetattr (STDIN_FILENO, termios_p: &term_attr) == 0) |
102 | { |
103 | old_flags = term_attr.c_lflag; |
104 | term_attr.c_lflag &= ~ECHO; |
105 | restore_flags = TRUE; |
106 | |
107 | if (tcsetattr (STDIN_FILENO, TCSAFLUSH, termios_p: &term_attr) != 0) |
108 | g_print (format: "Warning! Password will be echoed" ); |
109 | } |
110 | |
111 | #endif |
112 | |
113 | fgets(s: data, n: sizeof (data), stdin); |
114 | |
115 | #ifdef HAVE_TERMIOS_H |
116 | if (restore_flags) |
117 | { |
118 | term_attr.c_lflag = old_flags; |
119 | tcsetattr (STDIN_FILENO, TCSAFLUSH, termios_p: &term_attr); |
120 | } |
121 | #endif |
122 | |
123 | len = strlen (s: data); |
124 | if (len == 0) |
125 | { |
126 | g_print (format: "\n" ); |
127 | return NULL; |
128 | } |
129 | if (data[len-1] == '\n') |
130 | data[len-1] = 0; |
131 | |
132 | if (!echo) |
133 | g_print (format: "\n" ); |
134 | |
135 | if (*data == 0 && default_value) |
136 | return g_strdup (str: default_value); |
137 | return g_strdup (str: data); |
138 | } |
139 | |
140 | static void |
141 | ask_password_cb (GMountOperation *op, |
142 | const char *message, |
143 | const char *default_user, |
144 | const char *default_domain, |
145 | GAskPasswordFlags flags) |
146 | { |
147 | if ((flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED) && anonymous) |
148 | { |
149 | g_mount_operation_set_anonymous (op, TRUE); |
150 | } |
151 | else |
152 | { |
153 | char *s; |
154 | g_print (format: "%s\n" , message); |
155 | |
156 | if (flags & G_ASK_PASSWORD_NEED_USERNAME) |
157 | { |
158 | s = prompt_for (prompt: "User" , default_value: default_user, TRUE); |
159 | if (!s) |
160 | goto error; |
161 | g_mount_operation_set_username (op, username: s); |
162 | g_free (mem: s); |
163 | } |
164 | |
165 | if (flags & G_ASK_PASSWORD_NEED_DOMAIN) |
166 | { |
167 | s = prompt_for (prompt: "Domain" , default_value: default_domain, TRUE); |
168 | if (!s) |
169 | goto error; |
170 | g_mount_operation_set_domain (op, domain: s); |
171 | g_free (mem: s); |
172 | } |
173 | |
174 | if (flags & G_ASK_PASSWORD_NEED_PASSWORD) |
175 | { |
176 | s = prompt_for (prompt: "Password" , NULL, FALSE); |
177 | if (!s) |
178 | goto error; |
179 | g_mount_operation_set_password (op, password: s); |
180 | g_free (mem: s); |
181 | } |
182 | } |
183 | |
184 | if (flags & G_ASK_PASSWORD_TCRYPT) |
185 | { |
186 | if (tcrypt_pim) |
187 | g_mount_operation_set_pim (op, pim: tcrypt_pim); |
188 | if (tcrypt_hidden) |
189 | g_mount_operation_set_is_tcrypt_hidden_volume (op, TRUE); |
190 | if (tcrypt_system) |
191 | g_mount_operation_set_is_tcrypt_system_volume (op, TRUE); |
192 | } |
193 | |
194 | /* Only try anonymous access once. */ |
195 | if (anonymous && |
196 | GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state" )) == MOUNT_OP_ASKED) |
197 | { |
198 | g_object_set_data (G_OBJECT (op), key: "state" , GINT_TO_POINTER (MOUNT_OP_ABORTED)); |
199 | g_mount_operation_reply (op, result: G_MOUNT_OPERATION_ABORTED); |
200 | } |
201 | else |
202 | { |
203 | g_object_set_data (G_OBJECT (op), key: "state" , GINT_TO_POINTER (MOUNT_OP_ASKED)); |
204 | g_mount_operation_reply (op, result: G_MOUNT_OPERATION_HANDLED); |
205 | } |
206 | |
207 | return; |
208 | |
209 | error: |
210 | g_mount_operation_reply (op, result: G_MOUNT_OPERATION_ABORTED); |
211 | } |
212 | |
213 | static void |
214 | ask_question_cb (GMountOperation *op, |
215 | char *message, |
216 | char **choices, |
217 | gpointer user_data) |
218 | { |
219 | char **ptr = choices; |
220 | char *s; |
221 | int i, choice; |
222 | |
223 | g_print (format: "%s\n" , message); |
224 | |
225 | i = 1; |
226 | while (*ptr) |
227 | { |
228 | g_print (format: "[%d] %s\n" , i, *ptr++); |
229 | i++; |
230 | } |
231 | |
232 | s = prompt_for (prompt: "Choice" , NULL, TRUE); |
233 | if (!s) |
234 | goto error; |
235 | |
236 | choice = atoi (nptr: s); |
237 | if (choice > 0 && choice < i) |
238 | { |
239 | g_mount_operation_set_choice (op, choice: choice - 1); |
240 | g_mount_operation_reply (op, result: G_MOUNT_OPERATION_HANDLED); |
241 | } |
242 | g_free (mem: s); |
243 | |
244 | return; |
245 | |
246 | error: |
247 | g_mount_operation_reply (op, result: G_MOUNT_OPERATION_ABORTED); |
248 | } |
249 | |
250 | static void |
251 | mount_mountable_done_cb (GObject *object, |
252 | GAsyncResult *res, |
253 | gpointer user_data) |
254 | { |
255 | GFile *target; |
256 | GError *error = NULL; |
257 | GMountOperation *op = user_data; |
258 | |
259 | target = g_file_mount_mountable_finish (G_FILE (object), result: res, error: &error); |
260 | |
261 | if (target == NULL) |
262 | { |
263 | success = FALSE; |
264 | if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state" )) == MOUNT_OP_ABORTED) |
265 | print_file_error (G_FILE (object), _("Anonymous access denied" )); |
266 | else if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_FAILED_HANDLED)) |
267 | print_file_error (G_FILE (object), message: error->message); |
268 | |
269 | g_error_free (error); |
270 | } |
271 | else |
272 | g_object_unref (object: target); |
273 | |
274 | g_object_unref (object: op); |
275 | |
276 | outstanding_mounts--; |
277 | |
278 | if (outstanding_mounts == 0) |
279 | g_main_loop_quit (loop: main_loop); |
280 | } |
281 | |
282 | static void |
283 | mount_done_cb (GObject *object, |
284 | GAsyncResult *res, |
285 | gpointer user_data) |
286 | { |
287 | gboolean succeeded; |
288 | GError *error = NULL; |
289 | GMountOperation *op = user_data; |
290 | |
291 | succeeded = g_file_mount_enclosing_volume_finish (G_FILE (object), result: res, error: &error); |
292 | |
293 | if (!succeeded) |
294 | { |
295 | success = FALSE; |
296 | if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state" )) == MOUNT_OP_ABORTED) |
297 | print_file_error (G_FILE (object), _("Anonymous access denied" )); |
298 | else if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_FAILED_HANDLED)) |
299 | print_file_error (G_FILE (object), message: error->message); |
300 | |
301 | g_error_free (error); |
302 | } |
303 | |
304 | g_object_unref (object: op); |
305 | |
306 | outstanding_mounts--; |
307 | |
308 | if (outstanding_mounts == 0) |
309 | g_main_loop_quit (loop: main_loop); |
310 | } |
311 | |
312 | static GMountOperation * |
313 | new_mount_op (void) |
314 | { |
315 | GMountOperation *op; |
316 | |
317 | op = g_mount_operation_new (); |
318 | |
319 | g_object_set_data (G_OBJECT (op), key: "state" , GINT_TO_POINTER (MOUNT_OP_NONE)); |
320 | |
321 | g_signal_connect (op, "ask_password" , G_CALLBACK (ask_password_cb), NULL); |
322 | g_signal_connect (op, "ask_question" , G_CALLBACK (ask_question_cb), NULL); |
323 | |
324 | /* TODO: we *should* also connect to the "aborted" signal but since the |
325 | * main thread is blocked handling input we won't get that signal anyway... |
326 | */ |
327 | |
328 | return op; |
329 | } |
330 | |
331 | |
332 | static void |
333 | mount (GFile *file) |
334 | { |
335 | GMountOperation *op; |
336 | |
337 | if (file == NULL) |
338 | return; |
339 | |
340 | op = new_mount_op (); |
341 | |
342 | if (mount_mountable) |
343 | g_file_mount_mountable (file, flags: 0, mount_operation: op, NULL, callback: mount_mountable_done_cb, user_data: op); |
344 | else |
345 | g_file_mount_enclosing_volume (location: file, flags: 0, mount_operation: op, NULL, callback: mount_done_cb, user_data: op); |
346 | |
347 | outstanding_mounts++; |
348 | } |
349 | |
350 | static void |
351 | unmount_done_cb (GObject *object, |
352 | GAsyncResult *res, |
353 | gpointer user_data) |
354 | { |
355 | gboolean succeeded; |
356 | GError *error = NULL; |
357 | GFile *file = G_FILE (user_data); |
358 | |
359 | succeeded = g_mount_unmount_with_operation_finish (G_MOUNT (object), result: res, error: &error); |
360 | |
361 | g_object_unref (G_MOUNT (object)); |
362 | |
363 | if (!succeeded) |
364 | { |
365 | print_file_error (file, message: error->message); |
366 | success = FALSE; |
367 | g_error_free (error); |
368 | } |
369 | |
370 | g_object_unref (object: file); |
371 | |
372 | outstanding_mounts--; |
373 | |
374 | if (outstanding_mounts == 0) |
375 | g_main_loop_quit (loop: main_loop); |
376 | } |
377 | |
378 | static void |
379 | unmount (GFile *file) |
380 | { |
381 | GMount *mount; |
382 | GError *error = NULL; |
383 | GMountOperation *mount_op; |
384 | GMountUnmountFlags flags; |
385 | |
386 | if (file == NULL) |
387 | return; |
388 | |
389 | mount = g_file_find_enclosing_mount (file, NULL, error: &error); |
390 | if (mount == NULL) |
391 | { |
392 | print_file_error (file, message: error->message); |
393 | success = FALSE; |
394 | g_error_free (error); |
395 | return; |
396 | } |
397 | |
398 | mount_op = new_mount_op (); |
399 | flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE; |
400 | g_mount_unmount_with_operation (mount, flags, mount_operation: mount_op, NULL, callback: unmount_done_cb, g_object_ref (file)); |
401 | g_object_unref (object: mount_op); |
402 | |
403 | outstanding_mounts++; |
404 | } |
405 | |
406 | static void |
407 | eject_done_cb (GObject *object, |
408 | GAsyncResult *res, |
409 | gpointer user_data) |
410 | { |
411 | gboolean succeeded; |
412 | GError *error = NULL; |
413 | GFile *file = G_FILE (user_data); |
414 | |
415 | succeeded = g_mount_eject_with_operation_finish (G_MOUNT (object), result: res, error: &error); |
416 | |
417 | g_object_unref (G_MOUNT (object)); |
418 | |
419 | if (!succeeded) |
420 | { |
421 | print_file_error (file, message: error->message); |
422 | success = FALSE; |
423 | g_error_free (error); |
424 | } |
425 | |
426 | g_object_unref (object: file); |
427 | |
428 | outstanding_mounts--; |
429 | |
430 | if (outstanding_mounts == 0) |
431 | g_main_loop_quit (loop: main_loop); |
432 | } |
433 | |
434 | static void |
435 | eject (GFile *file) |
436 | { |
437 | GMount *mount; |
438 | GError *error = NULL; |
439 | GMountOperation *mount_op; |
440 | GMountUnmountFlags flags; |
441 | |
442 | if (file == NULL) |
443 | return; |
444 | |
445 | mount = g_file_find_enclosing_mount (file, NULL, error: &error); |
446 | if (mount == NULL) |
447 | { |
448 | print_file_error (file, message: error->message); |
449 | success = FALSE; |
450 | g_error_free (error); |
451 | return; |
452 | } |
453 | |
454 | mount_op = new_mount_op (); |
455 | flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE; |
456 | g_mount_eject_with_operation (mount, flags, mount_operation: mount_op, NULL, callback: eject_done_cb, g_object_ref (file)); |
457 | g_object_unref (object: mount_op); |
458 | |
459 | outstanding_mounts++; |
460 | } |
461 | |
462 | static void |
463 | stop_with_device_file_cb (GObject *object, |
464 | GAsyncResult *res, |
465 | gpointer user_data) |
466 | { |
467 | GError *error = NULL; |
468 | gchar *device_path = user_data; |
469 | |
470 | if (!g_drive_stop_finish (G_DRIVE (object), result: res, error: &error)) |
471 | { |
472 | print_error (format: "%s: %s" , device_path, error->message); |
473 | g_error_free (error); |
474 | success = FALSE; |
475 | } |
476 | |
477 | g_free (mem: device_path); |
478 | |
479 | outstanding_mounts--; |
480 | |
481 | if (outstanding_mounts == 0) |
482 | g_main_loop_quit (loop: main_loop); |
483 | } |
484 | |
485 | static void |
486 | stop_with_device_file (const char *device_file) |
487 | { |
488 | GList *drives; |
489 | GList *l; |
490 | |
491 | drives = g_volume_monitor_get_connected_drives (volume_monitor); |
492 | for (l = drives; l != NULL; l = l->next) |
493 | { |
494 | GDrive *drive = G_DRIVE (l->data); |
495 | gchar *id; |
496 | |
497 | id = g_drive_get_identifier (drive, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); |
498 | if (g_strcmp0 (str1: id, str2: device_file) == 0) |
499 | { |
500 | GMountOperation *op; |
501 | GMountUnmountFlags flags; |
502 | |
503 | op = new_mount_op (); |
504 | flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE; |
505 | g_drive_stop (drive, |
506 | flags, |
507 | mount_operation: op, |
508 | NULL, |
509 | callback: stop_with_device_file_cb, |
510 | g_steal_pointer (&id)); |
511 | g_object_unref (object: op); |
512 | |
513 | outstanding_mounts++; |
514 | } |
515 | |
516 | g_free (mem: id); |
517 | } |
518 | g_list_free_full (list: drives, free_func: g_object_unref); |
519 | |
520 | if (outstanding_mounts == 0) |
521 | { |
522 | print_error (format: "%s: %s" , device_file, _("No drive for device file" )); |
523 | success = FALSE; |
524 | } |
525 | } |
526 | |
527 | static gboolean |
528 | iterate_gmain_timeout_function (gpointer data) |
529 | { |
530 | g_main_loop_quit (loop: main_loop); |
531 | return FALSE; |
532 | } |
533 | |
534 | static void |
535 | iterate_gmain(void) |
536 | { |
537 | g_timeout_add (interval: 500, function: iterate_gmain_timeout_function, NULL); |
538 | g_main_loop_run (loop: main_loop); |
539 | } |
540 | |
541 | static void |
542 | show_themed_icon_names (GThemedIcon *icon, gboolean symbolic, int indent) |
543 | { |
544 | char **names; |
545 | char **iter; |
546 | |
547 | g_print (format: "%*s%sthemed icons:" , indent, " " , symbolic ? "symbolic " : "" ); |
548 | |
549 | names = NULL; |
550 | |
551 | g_object_get (object: icon, first_property_name: "names" , &names, NULL); |
552 | |
553 | for (iter = names; *iter; iter++) |
554 | g_print (format: " [%s]" , *iter); |
555 | |
556 | g_print (format: "\n" ); |
557 | g_strfreev (str_array: names); |
558 | } |
559 | |
560 | /* don't copy-paste this code */ |
561 | static char * |
562 | get_type_name (gpointer object) |
563 | { |
564 | const char *type_name; |
565 | char *ret; |
566 | |
567 | type_name = g_type_name (G_TYPE_FROM_INSTANCE (object)); |
568 | if (strcmp (s1: "GProxyDrive" , s2: type_name) == 0) |
569 | { |
570 | ret = g_strdup_printf (format: "%s (%s)" , |
571 | type_name, |
572 | (const char *) g_object_get_data (G_OBJECT (object), |
573 | key: "g-proxy-drive-volume-monitor-name" )); |
574 | } |
575 | else if (strcmp (s1: "GProxyVolume" , s2: type_name) == 0) |
576 | { |
577 | ret = g_strdup_printf (format: "%s (%s)" , |
578 | type_name, |
579 | (const char *) g_object_get_data (G_OBJECT (object), |
580 | key: "g-proxy-volume-volume-monitor-name" )); |
581 | } |
582 | else if (strcmp (s1: "GProxyMount" , s2: type_name) == 0) |
583 | { |
584 | ret = g_strdup_printf (format: "%s (%s)" , |
585 | type_name, |
586 | (const char *) g_object_get_data (G_OBJECT (object), |
587 | key: "g-proxy-mount-volume-monitor-name" )); |
588 | } |
589 | else if (strcmp (s1: "GProxyShadowMount" , s2: type_name) == 0) |
590 | { |
591 | ret = g_strdup_printf (format: "%s (%s)" , |
592 | type_name, |
593 | (const char *) g_object_get_data (G_OBJECT (object), |
594 | key: "g-proxy-shadow-mount-volume-monitor-name" )); |
595 | } |
596 | else |
597 | { |
598 | ret = g_strdup (str: type_name); |
599 | } |
600 | |
601 | return ret; |
602 | } |
603 | |
604 | static void |
605 | list_mounts (GList *mounts, |
606 | int indent, |
607 | gboolean only_with_no_volume) |
608 | { |
609 | GList *l; |
610 | int c; |
611 | GMount *mount; |
612 | GVolume *volume; |
613 | char *name, *uuid, *uri; |
614 | GFile *root, *default_location; |
615 | GIcon *icon; |
616 | char **x_content_types; |
617 | char *type_name; |
618 | const gchar *sort_key; |
619 | |
620 | for (c = 0, l = mounts; l != NULL; l = l->next, c++) |
621 | { |
622 | mount = (GMount *) l->data; |
623 | |
624 | if (only_with_no_volume) |
625 | { |
626 | volume = g_mount_get_volume (mount); |
627 | if (volume != NULL) |
628 | { |
629 | g_object_unref (object: volume); |
630 | continue; |
631 | } |
632 | } |
633 | |
634 | name = g_mount_get_name (mount); |
635 | root = g_mount_get_root (mount); |
636 | uri = g_file_get_uri (file: root); |
637 | |
638 | g_print (format: "%*sMount(%d): %s -> %s\n" , indent, "" , c, name, uri); |
639 | |
640 | type_name = get_type_name (object: mount); |
641 | g_print (format: "%*sType: %s\n" , indent+2, "" , type_name); |
642 | g_free (mem: type_name); |
643 | |
644 | if (extra_detail) |
645 | { |
646 | uuid = g_mount_get_uuid (mount); |
647 | if (uuid) |
648 | g_print (format: "%*suuid=%s\n" , indent + 2, "" , uuid); |
649 | |
650 | default_location = g_mount_get_default_location (mount); |
651 | if (default_location) |
652 | { |
653 | char *loc_uri = g_file_get_uri (file: default_location); |
654 | g_print (format: "%*sdefault_location=%s\n" , indent + 2, "" , loc_uri); |
655 | g_free (mem: loc_uri); |
656 | g_object_unref (object: default_location); |
657 | } |
658 | |
659 | icon = g_mount_get_icon (mount); |
660 | if (icon) |
661 | { |
662 | if (G_IS_THEMED_ICON (icon)) |
663 | show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent: indent + 2); |
664 | |
665 | g_object_unref (object: icon); |
666 | } |
667 | |
668 | icon = g_mount_get_symbolic_icon (mount); |
669 | if (icon) |
670 | { |
671 | if (G_IS_THEMED_ICON (icon)) |
672 | show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent: indent + 2); |
673 | |
674 | g_object_unref (object: icon); |
675 | } |
676 | |
677 | x_content_types = g_mount_guess_content_type_sync (mount, FALSE, NULL, NULL); |
678 | if (x_content_types != NULL && g_strv_length (str_array: x_content_types) > 0) |
679 | { |
680 | int n; |
681 | g_print (format: "%*sx_content_types:" , indent + 2, "" ); |
682 | for (n = 0; x_content_types[n] != NULL; n++) |
683 | g_print (format: " %s" , x_content_types[n]); |
684 | g_print (format: "\n" ); |
685 | } |
686 | g_strfreev (str_array: x_content_types); |
687 | |
688 | g_print (format: "%*scan_unmount=%d\n" , indent + 2, "" , g_mount_can_unmount (mount)); |
689 | g_print (format: "%*scan_eject=%d\n" , indent + 2, "" , g_mount_can_eject (mount)); |
690 | g_print (format: "%*sis_shadowed=%d\n" , indent + 2, "" , g_mount_is_shadowed (mount)); |
691 | sort_key = g_mount_get_sort_key (mount); |
692 | if (sort_key != NULL) |
693 | g_print (format: "%*ssort_key=%s\n" , indent + 2, "" , sort_key); |
694 | g_free (mem: uuid); |
695 | } |
696 | |
697 | g_object_unref (object: root); |
698 | g_free (mem: name); |
699 | g_free (mem: uri); |
700 | } |
701 | } |
702 | |
703 | static void |
704 | list_volumes (GList *volumes, |
705 | int indent, |
706 | gboolean only_with_no_drive) |
707 | { |
708 | GList *l, *mounts; |
709 | int c, i; |
710 | GMount *mount; |
711 | GVolume *volume; |
712 | GDrive *drive; |
713 | char *name; |
714 | char *uuid; |
715 | GFile *activation_root; |
716 | char **ids; |
717 | GIcon *icon; |
718 | char *type_name; |
719 | const gchar *sort_key; |
720 | |
721 | for (c = 0, l = volumes; l != NULL; l = l->next, c++) |
722 | { |
723 | volume = (GVolume *) l->data; |
724 | |
725 | if (only_with_no_drive) |
726 | { |
727 | drive = g_volume_get_drive (volume); |
728 | if (drive != NULL) |
729 | { |
730 | g_object_unref (object: drive); |
731 | continue; |
732 | } |
733 | } |
734 | |
735 | name = g_volume_get_name (volume); |
736 | |
737 | g_print (format: "%*sVolume(%d): %s\n" , indent, "" , c, name); |
738 | g_free (mem: name); |
739 | |
740 | type_name = get_type_name (object: volume); |
741 | g_print (format: "%*sType: %s\n" , indent+2, "" , type_name); |
742 | g_free (mem: type_name); |
743 | |
744 | if (extra_detail) |
745 | { |
746 | ids = g_volume_enumerate_identifiers (volume); |
747 | if (ids && ids[0] != NULL) |
748 | { |
749 | g_print (format: "%*sids:\n" , indent+2, "" ); |
750 | for (i = 0; ids[i] != NULL; i++) |
751 | { |
752 | char *id = g_volume_get_identifier (volume, |
753 | kind: ids[i]); |
754 | g_print (format: "%*s %s: '%s'\n" , indent+2, "" , ids[i], id); |
755 | g_free (mem: id); |
756 | } |
757 | } |
758 | g_strfreev (str_array: ids); |
759 | |
760 | uuid = g_volume_get_uuid (volume); |
761 | if (uuid) |
762 | g_print (format: "%*suuid=%s\n" , indent + 2, "" , uuid); |
763 | activation_root = g_volume_get_activation_root (volume); |
764 | if (activation_root) |
765 | { |
766 | char *uri; |
767 | uri = g_file_get_uri (file: activation_root); |
768 | g_print (format: "%*sactivation_root=%s\n" , indent + 2, "" , uri); |
769 | g_free (mem: uri); |
770 | g_object_unref (object: activation_root); |
771 | } |
772 | icon = g_volume_get_icon (volume); |
773 | if (icon) |
774 | { |
775 | if (G_IS_THEMED_ICON (icon)) |
776 | show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent: indent + 2); |
777 | |
778 | g_object_unref (object: icon); |
779 | } |
780 | |
781 | icon = g_volume_get_symbolic_icon (volume); |
782 | if (icon) |
783 | { |
784 | if (G_IS_THEMED_ICON (icon)) |
785 | show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent: indent + 2); |
786 | |
787 | g_object_unref (object: icon); |
788 | } |
789 | |
790 | g_print (format: "%*scan_mount=%d\n" , indent + 2, "" , g_volume_can_mount (volume)); |
791 | g_print (format: "%*scan_eject=%d\n" , indent + 2, "" , g_volume_can_eject (volume)); |
792 | g_print (format: "%*sshould_automount=%d\n" , indent + 2, "" , g_volume_should_automount (volume)); |
793 | sort_key = g_volume_get_sort_key (volume); |
794 | if (sort_key != NULL) |
795 | g_print (format: "%*ssort_key=%s\n" , indent + 2, "" , sort_key); |
796 | g_free (mem: uuid); |
797 | } |
798 | |
799 | mount = g_volume_get_mount (volume); |
800 | if (mount) |
801 | { |
802 | mounts = g_list_prepend (NULL, data: mount); |
803 | list_mounts (mounts, indent: indent + 2, FALSE); |
804 | g_list_free (list: mounts); |
805 | g_object_unref (object: mount); |
806 | } |
807 | } |
808 | } |
809 | |
810 | static void |
811 | list_drives (GList *drives, |
812 | int indent) |
813 | { |
814 | GList *volumes, *l; |
815 | int c, i; |
816 | GDrive *drive; |
817 | char *name; |
818 | char **ids; |
819 | GIcon *icon; |
820 | char *type_name; |
821 | const gchar *sort_key; |
822 | |
823 | for (c = 0, l = drives; l != NULL; l = l->next, c++) |
824 | { |
825 | drive = (GDrive *) l->data; |
826 | name = g_drive_get_name (drive); |
827 | |
828 | g_print (format: "%*sDrive(%d): %s\n" , indent, "" , c, name); |
829 | g_free (mem: name); |
830 | |
831 | type_name = get_type_name (object: drive); |
832 | g_print (format: "%*sType: %s\n" , indent+2, "" , type_name); |
833 | g_free (mem: type_name); |
834 | |
835 | if (extra_detail) |
836 | { |
837 | GEnumValue *enum_value; |
838 | gpointer klass; |
839 | |
840 | ids = g_drive_enumerate_identifiers (drive); |
841 | if (ids && ids[0] != NULL) |
842 | { |
843 | g_print (format: "%*sids:\n" , indent+2, "" ); |
844 | for (i = 0; ids[i] != NULL; i++) |
845 | { |
846 | char *id = g_drive_get_identifier (drive, |
847 | kind: ids[i]); |
848 | g_print (format: "%*s %s: '%s'\n" , indent+2, "" , ids[i], id); |
849 | g_free (mem: id); |
850 | } |
851 | } |
852 | g_strfreev (str_array: ids); |
853 | |
854 | icon = g_drive_get_icon (drive); |
855 | if (icon) |
856 | { |
857 | if (G_IS_THEMED_ICON (icon)) |
858 | show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent: indent + 2); |
859 | g_object_unref (object: icon); |
860 | } |
861 | |
862 | icon = g_drive_get_symbolic_icon (drive); |
863 | if (icon) |
864 | { |
865 | if (G_IS_THEMED_ICON (icon)) |
866 | show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent: indent + 2); |
867 | |
868 | g_object_unref (object: icon); |
869 | } |
870 | |
871 | g_print (format: "%*sis_removable=%d\n" , indent + 2, "" , g_drive_is_removable (drive)); |
872 | g_print (format: "%*sis_media_removable=%d\n" , indent + 2, "" , g_drive_is_media_removable (drive)); |
873 | g_print (format: "%*shas_media=%d\n" , indent + 2, "" , g_drive_has_media (drive)); |
874 | g_print (format: "%*sis_media_check_automatic=%d\n" , indent + 2, "" , g_drive_is_media_check_automatic (drive)); |
875 | g_print (format: "%*scan_poll_for_media=%d\n" , indent + 2, "" , g_drive_can_poll_for_media (drive)); |
876 | g_print (format: "%*scan_eject=%d\n" , indent + 2, "" , g_drive_can_eject (drive)); |
877 | g_print (format: "%*scan_start=%d\n" , indent + 2, "" , g_drive_can_start (drive)); |
878 | g_print (format: "%*scan_stop=%d\n" , indent + 2, "" , g_drive_can_stop (drive)); |
879 | |
880 | enum_value = NULL; |
881 | klass = g_type_class_ref (type: G_TYPE_DRIVE_START_STOP_TYPE); |
882 | if (klass != NULL) |
883 | { |
884 | enum_value = g_enum_get_value (enum_class: klass, value: g_drive_get_start_stop_type (drive)); |
885 | g_print (format: "%*sstart_stop_type=%s\n" , indent + 2, "" , |
886 | enum_value != NULL ? enum_value->value_nick : "UNKNOWN" ); |
887 | g_type_class_unref (g_class: klass); |
888 | } |
889 | |
890 | sort_key = g_drive_get_sort_key (drive); |
891 | if (sort_key != NULL) |
892 | g_print (format: "%*ssort_key=%s\n" , indent + 2, "" , sort_key); |
893 | } |
894 | volumes = g_drive_get_volumes (drive); |
895 | list_volumes (volumes, indent: indent + 2, FALSE); |
896 | g_list_free_full (list: volumes, free_func: g_object_unref); |
897 | } |
898 | } |
899 | |
900 | |
901 | static void |
902 | list_monitor_items (void) |
903 | { |
904 | GList *drives, *volumes, *mounts; |
905 | |
906 | /* populate gvfs network mounts */ |
907 | iterate_gmain(); |
908 | |
909 | drives = g_volume_monitor_get_connected_drives (volume_monitor); |
910 | list_drives (drives, indent: 0); |
911 | g_list_free_full (list: drives, free_func: g_object_unref); |
912 | |
913 | volumes = g_volume_monitor_get_volumes (volume_monitor); |
914 | list_volumes (volumes, indent: 0, TRUE); |
915 | g_list_free_full (list: volumes, free_func: g_object_unref); |
916 | |
917 | mounts = g_volume_monitor_get_mounts (volume_monitor); |
918 | list_mounts (mounts, indent: 0, TRUE); |
919 | g_list_free_full (list: mounts, free_func: g_object_unref); |
920 | } |
921 | |
922 | static void |
923 | unmount_all_with_scheme (const char *scheme) |
924 | { |
925 | GList *mounts; |
926 | GList *l; |
927 | |
928 | /* populate gvfs network mounts */ |
929 | iterate_gmain(); |
930 | |
931 | mounts = g_volume_monitor_get_mounts (volume_monitor); |
932 | for (l = mounts; l != NULL; l = l->next) { |
933 | GMount *mount = G_MOUNT (l->data); |
934 | GFile *root; |
935 | |
936 | root = g_mount_get_root (mount); |
937 | if (g_file_has_uri_scheme (file: root, uri_scheme: scheme)) { |
938 | unmount (file: root); |
939 | } |
940 | g_object_unref (object: root); |
941 | } |
942 | g_list_free_full (list: mounts, free_func: g_object_unref); |
943 | } |
944 | |
945 | static void |
946 | mount_with_device_file_cb (GObject *object, |
947 | GAsyncResult *res, |
948 | gpointer user_data) |
949 | { |
950 | GVolume *volume; |
951 | gboolean succeeded; |
952 | GError *error = NULL; |
953 | gchar *id = (gchar *)user_data; |
954 | |
955 | volume = G_VOLUME (object); |
956 | |
957 | succeeded = g_volume_mount_finish (volume, result: res, error: &error); |
958 | |
959 | if (!succeeded) |
960 | { |
961 | print_error (format: "%s: %s" , id, error->message); |
962 | g_error_free (error); |
963 | success = FALSE; |
964 | } |
965 | |
966 | g_free (mem: id); |
967 | |
968 | outstanding_mounts--; |
969 | |
970 | if (outstanding_mounts == 0) |
971 | g_main_loop_quit (loop: main_loop); |
972 | } |
973 | |
974 | static void |
975 | mount_with_id (const char *id) |
976 | { |
977 | GList *volumes; |
978 | GList *l; |
979 | |
980 | volumes = g_volume_monitor_get_volumes (volume_monitor); |
981 | for (l = volumes; l != NULL; l = l->next) |
982 | { |
983 | GVolume *volume = G_VOLUME (l->data); |
984 | gchar *device; |
985 | gchar *uuid; |
986 | |
987 | device = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); |
988 | uuid = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UUID); |
989 | if (g_strcmp0 (str1: device, str2: id) == 0 || g_strcmp0 (str1: uuid, str2: id) == 0) |
990 | { |
991 | GMountOperation *op; |
992 | |
993 | op = new_mount_op (); |
994 | |
995 | g_volume_mount (volume, |
996 | flags: G_MOUNT_MOUNT_NONE, |
997 | mount_operation: op, |
998 | NULL, |
999 | callback: mount_with_device_file_cb, |
1000 | user_data: g_strdup (str: id)); |
1001 | |
1002 | g_object_unref (object: op); |
1003 | |
1004 | outstanding_mounts++; |
1005 | } |
1006 | |
1007 | g_free (mem: device); |
1008 | g_free (mem: uuid); |
1009 | } |
1010 | g_list_free_full (list: volumes, free_func: g_object_unref); |
1011 | |
1012 | if (outstanding_mounts == 0) |
1013 | { |
1014 | print_error (format: "%s: %s" , id, _("No volume for given ID" )); |
1015 | success = FALSE; |
1016 | } |
1017 | } |
1018 | |
1019 | static void |
1020 | monitor_print_mount (GMount *mount) |
1021 | { |
1022 | if (extra_detail) |
1023 | { |
1024 | GList *l; |
1025 | l = g_list_prepend (NULL, data: mount); |
1026 | list_mounts (mounts: l, indent: 2, FALSE); |
1027 | g_list_free (list: l); |
1028 | g_print (format: "\n" ); |
1029 | } |
1030 | } |
1031 | |
1032 | static void |
1033 | monitor_print_volume (GVolume *volume) |
1034 | { |
1035 | if (extra_detail) |
1036 | { |
1037 | GList *l; |
1038 | l = g_list_prepend (NULL, data: volume); |
1039 | list_volumes (volumes: l, indent: 2, FALSE); |
1040 | g_list_free (list: l); |
1041 | g_print (format: "\n" ); |
1042 | } |
1043 | } |
1044 | |
1045 | static void |
1046 | monitor_print_drive (GDrive *drive) |
1047 | { |
1048 | if (extra_detail) |
1049 | { |
1050 | GList *l; |
1051 | l = g_list_prepend (NULL, data: drive); |
1052 | list_drives (drives: l, indent: 2); |
1053 | g_list_free (list: l); |
1054 | g_print (format: "\n" ); |
1055 | } |
1056 | } |
1057 | |
1058 | static void |
1059 | monitor_mount_added (GVolumeMonitor *volume_monitor, GMount *mount) |
1060 | { |
1061 | char *name; |
1062 | name = g_mount_get_name (mount); |
1063 | g_print (format: "Mount added: '%s'\n" , name); |
1064 | g_free (mem: name); |
1065 | monitor_print_mount (mount); |
1066 | } |
1067 | |
1068 | static void |
1069 | monitor_mount_removed (GVolumeMonitor *volume_monitor, GMount *mount) |
1070 | { |
1071 | char *name; |
1072 | name = g_mount_get_name (mount); |
1073 | g_print (format: "Mount removed: '%s'\n" , name); |
1074 | g_free (mem: name); |
1075 | monitor_print_mount (mount); |
1076 | } |
1077 | |
1078 | static void |
1079 | monitor_mount_changed (GVolumeMonitor *volume_monitor, GMount *mount) |
1080 | { |
1081 | char *name; |
1082 | name = g_mount_get_name (mount); |
1083 | g_print (format: "Mount changed: '%s'\n" , name); |
1084 | g_free (mem: name); |
1085 | monitor_print_mount (mount); |
1086 | } |
1087 | |
1088 | static void |
1089 | monitor_mount_pre_unmount (GVolumeMonitor *volume_monitor, GMount *mount) |
1090 | { |
1091 | char *name; |
1092 | name = g_mount_get_name (mount); |
1093 | g_print (format: "Mount pre-unmount: '%s'\n" , name); |
1094 | g_free (mem: name); |
1095 | monitor_print_mount (mount); |
1096 | } |
1097 | |
1098 | static void |
1099 | monitor_volume_added (GVolumeMonitor *volume_monitor, GVolume *volume) |
1100 | { |
1101 | char *name; |
1102 | name = g_volume_get_name (volume); |
1103 | g_print (format: "Volume added: '%s'\n" , name); |
1104 | g_free (mem: name); |
1105 | monitor_print_volume (volume); |
1106 | } |
1107 | |
1108 | static void |
1109 | monitor_volume_removed (GVolumeMonitor *volume_monitor, GVolume *volume) |
1110 | { |
1111 | char *name; |
1112 | name = g_volume_get_name (volume); |
1113 | g_print (format: "Volume removed: '%s'\n" , name); |
1114 | g_free (mem: name); |
1115 | monitor_print_volume (volume); |
1116 | } |
1117 | |
1118 | static void |
1119 | monitor_volume_changed (GVolumeMonitor *volume_monitor, GVolume *volume) |
1120 | { |
1121 | char *name; |
1122 | name = g_volume_get_name (volume); |
1123 | g_print (format: "Volume changed: '%s'\n" , name); |
1124 | g_free (mem: name); |
1125 | monitor_print_volume (volume); |
1126 | } |
1127 | |
1128 | static void |
1129 | monitor_drive_connected (GVolumeMonitor *volume_monitor, GDrive *drive) |
1130 | { |
1131 | char *name; |
1132 | name = g_drive_get_name (drive); |
1133 | g_print (format: "Drive connected: '%s'\n" , name); |
1134 | g_free (mem: name); |
1135 | monitor_print_drive (drive); |
1136 | } |
1137 | |
1138 | static void |
1139 | monitor_drive_disconnected (GVolumeMonitor *volume_monitor, GDrive *drive) |
1140 | { |
1141 | char *name; |
1142 | name = g_drive_get_name (drive); |
1143 | g_print (format: "Drive disconnected: '%s'\n" , name); |
1144 | g_free (mem: name); |
1145 | monitor_print_drive (drive); |
1146 | } |
1147 | |
1148 | static void |
1149 | monitor_drive_changed (GVolumeMonitor *volume_monitor, GDrive *drive) |
1150 | { |
1151 | char *name; |
1152 | name = g_drive_get_name (drive); |
1153 | g_print (format: "Drive changed: '%s'\n" , name); |
1154 | g_free (mem: name); |
1155 | monitor_print_drive (drive); |
1156 | } |
1157 | |
1158 | static void |
1159 | monitor_drive_eject_button (GVolumeMonitor *volume_monitor, GDrive *drive) |
1160 | { |
1161 | char *name; |
1162 | name = g_drive_get_name (drive); |
1163 | g_print (format: "Drive eject button: '%s'\n" , name); |
1164 | g_free (mem: name); |
1165 | } |
1166 | |
1167 | static void |
1168 | monitor (void) |
1169 | { |
1170 | g_signal_connect (volume_monitor, "mount-added" , (GCallback) monitor_mount_added, NULL); |
1171 | g_signal_connect (volume_monitor, "mount-removed" , (GCallback) monitor_mount_removed, NULL); |
1172 | g_signal_connect (volume_monitor, "mount-changed" , (GCallback) monitor_mount_changed, NULL); |
1173 | g_signal_connect (volume_monitor, "mount-pre-unmount" , (GCallback) monitor_mount_pre_unmount, NULL); |
1174 | g_signal_connect (volume_monitor, "volume-added" , (GCallback) monitor_volume_added, NULL); |
1175 | g_signal_connect (volume_monitor, "volume-removed" , (GCallback) monitor_volume_removed, NULL); |
1176 | g_signal_connect (volume_monitor, "volume-changed" , (GCallback) monitor_volume_changed, NULL); |
1177 | g_signal_connect (volume_monitor, "drive-connected" , (GCallback) monitor_drive_connected, NULL); |
1178 | g_signal_connect (volume_monitor, "drive-disconnected" , (GCallback) monitor_drive_disconnected, NULL); |
1179 | g_signal_connect (volume_monitor, "drive-changed" , (GCallback) monitor_drive_changed, NULL); |
1180 | g_signal_connect (volume_monitor, "drive-eject-button" , (GCallback) monitor_drive_eject_button, NULL); |
1181 | |
1182 | g_print (format: "Monitoring events. Press Ctrl+C to quit.\n" ); |
1183 | |
1184 | g_main_loop_run (loop: main_loop); |
1185 | } |
1186 | |
1187 | int |
1188 | handle_mount (int argc, char *argv[], gboolean do_help) |
1189 | { |
1190 | GOptionContext *context; |
1191 | gchar *param; |
1192 | GError *error = NULL; |
1193 | GFile *file; |
1194 | int i; |
1195 | |
1196 | g_set_prgname (prgname: "gio mount" ); |
1197 | |
1198 | /* Translators: commandline placeholder */ |
1199 | param = g_strdup_printf (format: "[%s…]" , _("LOCATION" )); |
1200 | context = g_option_context_new (parameter_string: param); |
1201 | g_free (mem: param); |
1202 | g_option_context_set_help_enabled (context, FALSE); |
1203 | g_option_context_set_summary (context, _("Mount or unmount the locations." )); |
1204 | g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); |
1205 | |
1206 | if (do_help) |
1207 | { |
1208 | show_help (context, NULL); |
1209 | g_option_context_free (context); |
1210 | return 0; |
1211 | } |
1212 | |
1213 | if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error)) |
1214 | { |
1215 | show_help (context, message: error->message); |
1216 | g_error_free (error); |
1217 | g_option_context_free (context); |
1218 | return 1; |
1219 | } |
1220 | |
1221 | main_loop = g_main_loop_new (NULL, FALSE); |
1222 | volume_monitor = g_volume_monitor_get (); |
1223 | |
1224 | if (mount_list) |
1225 | list_monitor_items (); |
1226 | else if (mount_id != NULL) |
1227 | mount_with_id (id: mount_id); |
1228 | else if (stop_device_file) |
1229 | stop_with_device_file (device_file: stop_device_file); |
1230 | else if (unmount_scheme != NULL) |
1231 | unmount_all_with_scheme (scheme: unmount_scheme); |
1232 | else if (mount_monitor) |
1233 | monitor (); |
1234 | else if (argc > 1) |
1235 | { |
1236 | for (i = 1; i < argc; i++) |
1237 | { |
1238 | file = g_file_new_for_commandline_arg (arg: argv[i]); |
1239 | if (mount_unmount) |
1240 | unmount (file); |
1241 | else if (mount_eject) |
1242 | eject (file); |
1243 | else |
1244 | mount (file); |
1245 | g_object_unref (object: file); |
1246 | } |
1247 | } |
1248 | else |
1249 | { |
1250 | show_help (context, _("No locations given" )); |
1251 | g_option_context_free (context); |
1252 | g_object_unref (object: volume_monitor); |
1253 | return 1; |
1254 | } |
1255 | |
1256 | g_option_context_free (context); |
1257 | |
1258 | if (outstanding_mounts > 0) |
1259 | g_main_loop_run (loop: main_loop); |
1260 | |
1261 | g_object_unref (object: volume_monitor); |
1262 | |
1263 | return success ? 0 : 2; |
1264 | } |
1265 | |