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