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 extra_detail = 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   G_OPTION_ENTRY_NULL
79 };
80 
81 static char *
prompt_for(const char * prompt,const char * default_value,gboolean echo)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 ("%s [%s]: ", prompt, default_value);
94   else
95     g_print ("%s: ", prompt);
96 
97   data[0] = 0;
98 
99 #ifdef HAVE_TERMIOS_H
100   restore_flags = FALSE;
101   if (!echo && tcgetattr (STDIN_FILENO, &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, &term_attr) != 0)
108         g_print ("Warning! Password will be echoed");
109     }
110 
111 #endif
112 
113   fgets(data, 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, &term_attr);
120     }
121 #endif
122 
123   len = strlen (data);
124   if (len == 0)
125     {
126       g_print ("\n");
127       return NULL;
128     }
129   if (data[len-1] == '\n')
130     data[len-1] = 0;
131 
132   if (!echo)
133     g_print ("\n");
134 
135   if (*data == 0 && default_value)
136     return g_strdup (default_value);
137   return g_strdup (data);
138 }
139 
140 static void
ask_password_cb(GMountOperation * op,const char * message,const char * default_user,const char * default_domain,GAskPasswordFlags flags)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 ("%s\n", message);
155 
156       if (flags & G_ASK_PASSWORD_NEED_USERNAME)
157         {
158           s = prompt_for ("User", default_user, TRUE);
159           if (!s)
160             goto error;
161           g_mount_operation_set_username (op, s);
162           g_free (s);
163         }
164 
165       if (flags & G_ASK_PASSWORD_NEED_DOMAIN)
166         {
167           s = prompt_for ("Domain", default_domain, TRUE);
168           if (!s)
169             goto error;
170           g_mount_operation_set_domain (op, s);
171           g_free (s);
172         }
173 
174       if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
175         {
176           s = prompt_for ("Password", NULL, FALSE);
177           if (!s)
178             goto error;
179           g_mount_operation_set_password (op, s);
180           g_free (s);
181         }
182     }
183 
184   if (flags & G_ASK_PASSWORD_TCRYPT)
185     {
186       if (tcrypt_pim)
187         g_mount_operation_set_pim (op, 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), "state", GINT_TO_POINTER (MOUNT_OP_ABORTED));
199       g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
200     }
201   else
202     {
203       g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_ASKED));
204       g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
205     }
206 
207   return;
208 
209 error:
210   g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
211 }
212 
213 static void
ask_question_cb(GMountOperation * op,char * message,char ** choices,gpointer user_data)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 ("%s\n", message);
224 
225   i = 1;
226   while (*ptr)
227     {
228       g_print ("[%d] %s\n", i, *ptr++);
229       i++;
230     }
231 
232   s = prompt_for ("Choice", NULL, TRUE);
233   if (!s)
234     goto error;
235 
236   choice = atoi (s);
237   if (choice > 0 && choice < i)
238     {
239       g_mount_operation_set_choice (op, choice - 1);
240       g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
241     }
242   g_free (s);
243 
244   return;
245 
246 error:
247   g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
248 }
249 
250 static void
mount_mountable_done_cb(GObject * object,GAsyncResult * res,gpointer user_data)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), res, &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, G_IO_ERROR_FAILED_HANDLED))
267         print_file_error (G_FILE (object), error->message);
268 
269       g_error_free (error);
270     }
271   else
272     g_object_unref (target);
273 
274   g_object_unref (op);
275 
276   outstanding_mounts--;
277 
278   if (outstanding_mounts == 0)
279     g_main_loop_quit (main_loop);
280 }
281 
282 static void
mount_done_cb(GObject * object,GAsyncResult * res,gpointer user_data)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), res, &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, G_IO_ERROR_FAILED_HANDLED))
299         print_file_error (G_FILE (object), error->message);
300 
301       g_error_free (error);
302     }
303 
304   g_object_unref (op);
305 
306   outstanding_mounts--;
307 
308   if (outstanding_mounts == 0)
309     g_main_loop_quit (main_loop);
310 }
311 
312 static GMountOperation *
new_mount_op(void)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), "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
mount(GFile * file)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, 0, op, NULL, mount_mountable_done_cb, op);
344   else
345     g_file_mount_enclosing_volume (file, 0, op, NULL, mount_done_cb, op);
346 
347   outstanding_mounts++;
348 }
349 
350 static void
unmount_done_cb(GObject * object,GAsyncResult * res,gpointer user_data)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), res, &error);
360 
361   g_object_unref (G_MOUNT (object));
362 
363   if (!succeeded)
364     {
365       print_file_error (file, error->message);
366       success = FALSE;
367       g_error_free (error);
368     }
369 
370   g_object_unref (file);
371 
372   outstanding_mounts--;
373 
374   if (outstanding_mounts == 0)
375     g_main_loop_quit (main_loop);
376 }
377 
378 static void
unmount(GFile * file)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);
390   if (mount == NULL)
391     {
392       print_file_error (file, 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_op, NULL, unmount_done_cb, g_object_ref (file));
401   g_object_unref (mount_op);
402 
403   outstanding_mounts++;
404 }
405 
406 static void
eject_done_cb(GObject * object,GAsyncResult * res,gpointer user_data)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), res, &error);
416 
417   g_object_unref (G_MOUNT (object));
418 
419   if (!succeeded)
420     {
421       print_file_error (file, error->message);
422       success = FALSE;
423       g_error_free (error);
424     }
425 
426   g_object_unref (file);
427 
428   outstanding_mounts--;
429 
430   if (outstanding_mounts == 0)
431     g_main_loop_quit (main_loop);
432 }
433 
434 static void
eject(GFile * file)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);
446   if (mount == NULL)
447     {
448       print_file_error (file, 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_op, NULL, eject_done_cb, g_object_ref (file));
457   g_object_unref (mount_op);
458 
459   outstanding_mounts++;
460 }
461 
462 static void
stop_with_device_file_cb(GObject * object,GAsyncResult * res,gpointer user_data)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), res, &error))
471     {
472       print_error ("%s: %s", device_path, error->message);
473       g_error_free (error);
474       success = FALSE;
475     }
476 
477   g_free (device_path);
478 
479   outstanding_mounts--;
480 
481   if (outstanding_mounts == 0)
482     g_main_loop_quit (main_loop);
483 }
484 
485 static void
stop_with_device_file(const char * device_file)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 (id, 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                         op,
508                         NULL,
509                         stop_with_device_file_cb,
510                         g_steal_pointer (&id));
511           g_object_unref (op);
512 
513           outstanding_mounts++;
514         }
515 
516       g_free (id);
517     }
518   g_list_free_full (drives, g_object_unref);
519 
520   if (outstanding_mounts == 0)
521     {
522       print_error ("%s: %s", device_file, _("No drive for device file"));
523       success = FALSE;
524     }
525 }
526 
527 static gboolean
iterate_gmain_timeout_function(gpointer data)528 iterate_gmain_timeout_function (gpointer data)
529 {
530   g_main_loop_quit (main_loop);
531   return FALSE;
532 }
533 
534 static void
iterate_gmain(void)535 iterate_gmain(void)
536 {
537   g_timeout_add (500, iterate_gmain_timeout_function, NULL);
538   g_main_loop_run (main_loop);
539 }
540 
541 static void
show_themed_icon_names(GThemedIcon * icon,gboolean symbolic,int indent)542 show_themed_icon_names (GThemedIcon *icon, gboolean symbolic, int indent)
543 {
544   char **names;
545   char **iter;
546 
547   g_print ("%*s%sthemed icons:", indent, " ", symbolic ? "symbolic " : "");
548 
549   names = NULL;
550 
551   g_object_get (icon, "names", &names, NULL);
552 
553   for (iter = names; *iter; iter++)
554     g_print ("  [%s]", *iter);
555 
556   g_print ("\n");
557   g_strfreev (names);
558 }
559 
560 /* don't copy-paste this code */
561 static char *
get_type_name(gpointer object)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 ("GProxyDrive", type_name) == 0)
569     {
570       ret = g_strdup_printf ("%s (%s)",
571                              type_name,
572                              (const char *) g_object_get_data (G_OBJECT (object),
573                                                                "g-proxy-drive-volume-monitor-name"));
574     }
575   else if (strcmp ("GProxyVolume", type_name) == 0)
576     {
577       ret = g_strdup_printf ("%s (%s)",
578                              type_name,
579                              (const char *) g_object_get_data (G_OBJECT (object),
580                                                                "g-proxy-volume-volume-monitor-name"));
581     }
582   else if (strcmp ("GProxyMount", type_name) == 0)
583     {
584       ret = g_strdup_printf ("%s (%s)",
585                              type_name,
586                              (const char *) g_object_get_data (G_OBJECT (object),
587                                                                "g-proxy-mount-volume-monitor-name"));
588     }
589   else if (strcmp ("GProxyShadowMount", type_name) == 0)
590     {
591       ret = g_strdup_printf ("%s (%s)",
592                              type_name,
593                              (const char *) g_object_get_data (G_OBJECT (object),
594                                                                "g-proxy-shadow-mount-volume-monitor-name"));
595     }
596   else
597     {
598       ret = g_strdup (type_name);
599     }
600 
601   return ret;
602 }
603 
604 static void
list_mounts(GList * mounts,int indent,gboolean only_with_no_volume)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 (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 (root);
637 
638       g_print ("%*sMount(%d): %s -> %s\n", indent, "", c, name, uri);
639 
640       type_name = get_type_name (mount);
641       g_print ("%*sType: %s\n", indent+2, "", type_name);
642       g_free (type_name);
643 
644       if (extra_detail)
645         {
646           uuid = g_mount_get_uuid (mount);
647           if (uuid)
648             g_print ("%*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 (default_location);
654               g_print ("%*sdefault_location=%s\n", indent + 2, "", loc_uri);
655               g_free (loc_uri);
656               g_object_unref (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 + 2);
664 
665               g_object_unref (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 + 2);
673 
674               g_object_unref (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 (x_content_types) > 0)
679             {
680               int n;
681               g_print ("%*sx_content_types:", indent + 2, "");
682               for (n = 0; x_content_types[n] != NULL; n++)
683                   g_print (" %s", x_content_types[n]);
684               g_print ("\n");
685             }
686           g_strfreev (x_content_types);
687 
688           g_print ("%*scan_unmount=%d\n", indent + 2, "", g_mount_can_unmount (mount));
689           g_print ("%*scan_eject=%d\n", indent + 2, "", g_mount_can_eject (mount));
690           g_print ("%*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 ("%*ssort_key=%s\n", indent + 2, "", sort_key);
694           g_free (uuid);
695         }
696 
697       g_object_unref (root);
698       g_free (name);
699       g_free (uri);
700     }
701 }
702 
703 static void
list_volumes(GList * volumes,int indent,gboolean only_with_no_drive)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 (drive);
731               continue;
732             }
733         }
734 
735       name = g_volume_get_name (volume);
736 
737       g_print ("%*sVolume(%d): %s\n", indent, "", c, name);
738       g_free (name);
739 
740       type_name = get_type_name (volume);
741       g_print ("%*sType: %s\n", indent+2, "", type_name);
742       g_free (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 ("%*sids:\n", indent+2, "");
750               for (i = 0; ids[i] != NULL; i++)
751                 {
752                   char *id = g_volume_get_identifier (volume,
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           uuid = g_volume_get_uuid (volume);
761           if (uuid)
762             g_print ("%*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 (activation_root);
768               g_print ("%*sactivation_root=%s\n", indent + 2, "", uri);
769               g_free (uri);
770               g_object_unref (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 + 2);
777 
778               g_object_unref (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 + 2);
786 
787               g_object_unref (icon);
788             }
789 
790           g_print ("%*scan_mount=%d\n", indent + 2, "", g_volume_can_mount (volume));
791           g_print ("%*scan_eject=%d\n", indent + 2, "", g_volume_can_eject (volume));
792           g_print ("%*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 ("%*ssort_key=%s\n", indent + 2, "", sort_key);
796           g_free (uuid);
797         }
798 
799       mount = g_volume_get_mount (volume);
800       if (mount)
801         {
802           mounts = g_list_prepend (NULL, mount);
803           list_mounts (mounts, indent + 2, FALSE);
804           g_list_free (mounts);
805           g_object_unref (mount);
806         }
807     }
808 }
809 
810 static void
list_drives(GList * drives,int indent)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 ("%*sDrive(%d): %s\n", indent, "", c, name);
829       g_free (name);
830 
831       type_name = get_type_name (drive);
832       g_print ("%*sType: %s\n", indent+2, "", type_name);
833       g_free (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 ("%*sids:\n", indent+2, "");
844               for (i = 0; ids[i] != NULL; i++)
845                 {
846                   char *id = g_drive_get_identifier (drive,
847                                                      ids[i]);
848                   g_print ("%*s %s: '%s'\n", indent+2, "", ids[i], id);
849                   g_free (id);
850                 }
851             }
852           g_strfreev (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 + 2);
859                   g_object_unref (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 + 2);
867 
868               g_object_unref (icon);
869             }
870 
871           g_print ("%*sis_removable=%d\n", indent + 2, "", g_drive_is_removable (drive));
872           g_print ("%*sis_media_removable=%d\n", indent + 2, "", g_drive_is_media_removable (drive));
873           g_print ("%*shas_media=%d\n", indent + 2, "", g_drive_has_media (drive));
874           g_print ("%*sis_media_check_automatic=%d\n", indent + 2, "", g_drive_is_media_check_automatic (drive));
875           g_print ("%*scan_poll_for_media=%d\n", indent + 2, "", g_drive_can_poll_for_media (drive));
876           g_print ("%*scan_eject=%d\n", indent + 2, "", g_drive_can_eject (drive));
877           g_print ("%*scan_start=%d\n", indent + 2, "", g_drive_can_start (drive));
878           g_print ("%*scan_stop=%d\n", indent + 2, "", g_drive_can_stop (drive));
879 
880           enum_value = NULL;
881           klass = g_type_class_ref (G_TYPE_DRIVE_START_STOP_TYPE);
882           if (klass != NULL)
883             {
884               enum_value = g_enum_get_value (klass, g_drive_get_start_stop_type (drive));
885               g_print ("%*sstart_stop_type=%s\n", indent + 2, "",
886                        enum_value != NULL ? enum_value->value_nick : "UNKNOWN");
887               g_type_class_unref (klass);
888             }
889 
890           sort_key = g_drive_get_sort_key (drive);
891           if (sort_key != NULL)
892             g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key);
893         }
894       volumes = g_drive_get_volumes (drive);
895       list_volumes (volumes, indent + 2, FALSE);
896       g_list_free_full (volumes, g_object_unref);
897     }
898 }
899 
900 
901 static void
list_monitor_items(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, 0);
911   g_list_free_full (drives, g_object_unref);
912 
913   volumes = g_volume_monitor_get_volumes (volume_monitor);
914   list_volumes (volumes, 0, TRUE);
915   g_list_free_full (volumes, g_object_unref);
916 
917   mounts = g_volume_monitor_get_mounts (volume_monitor);
918   list_mounts (mounts, 0, TRUE);
919   g_list_free_full (mounts, g_object_unref);
920 }
921 
922 static void
unmount_all_with_scheme(const char * scheme)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 (root, scheme)) {
938             unmount (root);
939     }
940     g_object_unref (root);
941   }
942   g_list_free_full (mounts, g_object_unref);
943 }
944 
945 static void
mount_with_device_file_cb(GObject * object,GAsyncResult * res,gpointer user_data)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, res, &error);
958 
959   if (!succeeded)
960     {
961       print_error ("%s: %s", id, error->message);
962       g_error_free (error);
963       success = FALSE;
964     }
965 
966   g_free (id);
967 
968   outstanding_mounts--;
969 
970   if (outstanding_mounts == 0)
971     g_main_loop_quit (main_loop);
972 }
973 
974 static void
mount_with_id(const char * id)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 (device, id) == 0 || g_strcmp0 (uuid, id) == 0)
990         {
991           GMountOperation *op;
992 
993           op = new_mount_op ();
994 
995           g_volume_mount (volume,
996                           G_MOUNT_MOUNT_NONE,
997                           op,
998                           NULL,
999                           mount_with_device_file_cb,
1000                           g_strdup (id));
1001 
1002           g_object_unref (op);
1003 
1004           outstanding_mounts++;
1005         }
1006 
1007       g_free (device);
1008       g_free (uuid);
1009     }
1010   g_list_free_full (volumes, g_object_unref);
1011 
1012   if (outstanding_mounts == 0)
1013     {
1014       print_error ("%s: %s", id, _("No volume for given ID"));
1015       success = FALSE;
1016     }
1017 }
1018 
1019 static void
monitor_print_mount(GMount * mount)1020 monitor_print_mount (GMount *mount)
1021 {
1022   if (extra_detail)
1023     {
1024       GList *l;
1025       l = g_list_prepend (NULL, mount);
1026       list_mounts (l, 2, FALSE);
1027       g_list_free (l);
1028       g_print ("\n");
1029     }
1030 }
1031 
1032 static void
monitor_print_volume(GVolume * volume)1033 monitor_print_volume (GVolume *volume)
1034 {
1035   if (extra_detail)
1036     {
1037       GList *l;
1038       l = g_list_prepend (NULL, volume);
1039       list_volumes (l, 2, FALSE);
1040       g_list_free (l);
1041       g_print ("\n");
1042     }
1043 }
1044 
1045 static void
monitor_print_drive(GDrive * drive)1046 monitor_print_drive (GDrive *drive)
1047 {
1048   if (extra_detail)
1049     {
1050       GList *l;
1051       l = g_list_prepend (NULL, drive);
1052       list_drives (l, 2);
1053       g_list_free (l);
1054       g_print ("\n");
1055     }
1056 }
1057 
1058 static void
monitor_mount_added(GVolumeMonitor * volume_monitor,GMount * mount)1059 monitor_mount_added (GVolumeMonitor *volume_monitor, GMount *mount)
1060 {
1061   char *name;
1062   name = g_mount_get_name (mount);
1063   g_print ("Mount added:        '%s'\n", name);
1064   g_free (name);
1065   monitor_print_mount (mount);
1066 }
1067 
1068 static void
monitor_mount_removed(GVolumeMonitor * volume_monitor,GMount * mount)1069 monitor_mount_removed (GVolumeMonitor *volume_monitor, GMount *mount)
1070 {
1071   char *name;
1072   name = g_mount_get_name (mount);
1073   g_print ("Mount removed:      '%s'\n", name);
1074   g_free (name);
1075   monitor_print_mount (mount);
1076 }
1077 
1078 static void
monitor_mount_changed(GVolumeMonitor * volume_monitor,GMount * mount)1079 monitor_mount_changed (GVolumeMonitor *volume_monitor, GMount *mount)
1080 {
1081   char *name;
1082   name = g_mount_get_name (mount);
1083   g_print ("Mount changed:      '%s'\n", name);
1084   g_free (name);
1085   monitor_print_mount (mount);
1086 }
1087 
1088 static void
monitor_mount_pre_unmount(GVolumeMonitor * volume_monitor,GMount * mount)1089 monitor_mount_pre_unmount (GVolumeMonitor *volume_monitor, GMount *mount)
1090 {
1091   char *name;
1092   name = g_mount_get_name (mount);
1093   g_print ("Mount pre-unmount:  '%s'\n", name);
1094   g_free (name);
1095   monitor_print_mount (mount);
1096 }
1097 
1098 static void
monitor_volume_added(GVolumeMonitor * volume_monitor,GVolume * volume)1099 monitor_volume_added (GVolumeMonitor *volume_monitor, GVolume *volume)
1100 {
1101   char *name;
1102   name = g_volume_get_name (volume);
1103   g_print ("Volume added:       '%s'\n", name);
1104   g_free (name);
1105   monitor_print_volume (volume);
1106 }
1107 
1108 static void
monitor_volume_removed(GVolumeMonitor * volume_monitor,GVolume * volume)1109 monitor_volume_removed (GVolumeMonitor *volume_monitor, GVolume *volume)
1110 {
1111   char *name;
1112   name = g_volume_get_name (volume);
1113   g_print ("Volume removed:     '%s'\n", name);
1114   g_free (name);
1115   monitor_print_volume (volume);
1116 }
1117 
1118 static void
monitor_volume_changed(GVolumeMonitor * volume_monitor,GVolume * volume)1119 monitor_volume_changed (GVolumeMonitor *volume_monitor, GVolume *volume)
1120 {
1121   char *name;
1122   name = g_volume_get_name (volume);
1123   g_print ("Volume changed:     '%s'\n", name);
1124   g_free (name);
1125   monitor_print_volume (volume);
1126 }
1127 
1128 static void
monitor_drive_connected(GVolumeMonitor * volume_monitor,GDrive * drive)1129 monitor_drive_connected (GVolumeMonitor *volume_monitor, GDrive *drive)
1130 {
1131   char *name;
1132   name = g_drive_get_name (drive);
1133   g_print ("Drive connected:    '%s'\n", name);
1134   g_free (name);
1135   monitor_print_drive (drive);
1136 }
1137 
1138 static void
monitor_drive_disconnected(GVolumeMonitor * volume_monitor,GDrive * drive)1139 monitor_drive_disconnected (GVolumeMonitor *volume_monitor, GDrive *drive)
1140 {
1141   char *name;
1142   name = g_drive_get_name (drive);
1143   g_print ("Drive disconnected: '%s'\n", name);
1144   g_free (name);
1145   monitor_print_drive (drive);
1146 }
1147 
1148 static void
monitor_drive_changed(GVolumeMonitor * volume_monitor,GDrive * drive)1149 monitor_drive_changed (GVolumeMonitor *volume_monitor, GDrive *drive)
1150 {
1151   char *name;
1152   name = g_drive_get_name (drive);
1153   g_print ("Drive changed:      '%s'\n", name);
1154   g_free (name);
1155   monitor_print_drive (drive);
1156 }
1157 
1158 static void
monitor_drive_eject_button(GVolumeMonitor * volume_monitor,GDrive * drive)1159 monitor_drive_eject_button (GVolumeMonitor *volume_monitor, GDrive *drive)
1160 {
1161   char *name;
1162   name = g_drive_get_name (drive);
1163   g_print ("Drive eject button: '%s'\n", name);
1164   g_free (name);
1165 }
1166 
1167 static void
monitor(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 ("Monitoring events. Press Ctrl+C to quit.\n");
1183 
1184   g_main_loop_run (main_loop);
1185 }
1186 
1187 int
handle_mount(int argc,char * argv[],gboolean do_help)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 ("gio mount");
1197 
1198   /* Translators: commandline placeholder */
1199   param = g_strdup_printf ("[%s…]", _("LOCATION"));
1200   context = g_option_context_new (param);
1201   g_free (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, &argv, &error))
1214     {
1215       show_help (context, 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 (mount_id);
1228   else if (stop_device_file)
1229     stop_with_device_file (stop_device_file);
1230   else if (unmount_scheme != NULL)
1231     unmount_all_with_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 (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 (file);
1246         }
1247     }
1248   else
1249     {
1250       show_help (context, _("No locations given"));
1251       g_option_context_free (context);
1252       g_object_unref (volume_monitor);
1253       return 1;
1254     }
1255 
1256   g_option_context_free (context);
1257 
1258   if (outstanding_mounts > 0)
1259     g_main_loop_run (main_loop);
1260 
1261   g_object_unref (volume_monitor);
1262 
1263   return success ? 0 : 2;
1264 }
1265