glib/gio/gio-tool-mount.c
Ondrej Holy 8c24b7cd6e gio-tool-mount: Allow mounting by the given UUID
"gio mount" only allows mounting volumes using device files, but not using
UUIDs. Volume monitors for various GVfs locations usually supports just UUIDs.
It would be handy to support them also for testing purposes (because
"g_file_mount_enclosing_volume()" does something else than "g_volume_mount()"
in case of shares provided by GOA volume monitor for example). Let's update
"-d" option to support also UUIDs.

https://gitlab.gnome.org/GNOME/gvfs/issues/251
2019-11-27 13:20:57 +01:00

1281 lines
34 KiB
C

/*
* Copyright 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include <gio/gio.h>
#include <gi18n.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#include "gio-tool.h"
#define STDIN_FILENO 0
typedef enum {
MOUNT_OP_NONE,
MOUNT_OP_ASKED,
MOUNT_OP_ABORTED
} MountOpState;
static int outstanding_mounts = 0;
static GMainLoop *main_loop;
static GVolumeMonitor *volume_monitor;
static gboolean mount_mountable = FALSE;
static gboolean mount_unmount = FALSE;
static gboolean mount_eject = FALSE;
static gboolean force = FALSE;
static gboolean anonymous = FALSE;
static gboolean mount_list = FALSE;
static gboolean extra_detail = FALSE;
static gboolean mount_monitor = FALSE;
static gboolean tcrypt_hidden = FALSE;
static gboolean tcrypt_system = FALSE;
static guint tcrypt_pim = 0;
static const char *unmount_scheme = NULL;
static const char *mount_id = NULL;
static const char *stop_device_file = NULL;
static gboolean success = TRUE;
static const GOptionEntry entries[] =
{
{ "mountable", 'm', 0, G_OPTION_ARG_NONE, &mount_mountable, N_("Mount as mountable"), NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &mount_id, N_("Mount volume with device file, or other identifier"), N_("ID") },
{ "unmount", 'u', 0, G_OPTION_ARG_NONE, &mount_unmount, N_("Unmount"), NULL},
{ "eject", 'e', 0, G_OPTION_ARG_NONE, &mount_eject, N_("Eject"), NULL},
{ "stop", 't', 0, G_OPTION_ARG_STRING, &stop_device_file, N_("Stop drive with device file"), N_("DEVICE") },
{ "unmount-scheme", 's', 0, G_OPTION_ARG_STRING, &unmount_scheme, N_("Unmount all mounts with the given scheme"), N_("SCHEME") },
{ "force", 'f', 0, G_OPTION_ARG_NONE, &force, N_("Ignore outstanding file operations when unmounting or ejecting"), NULL },
{ "anonymous", 'a', 0, G_OPTION_ARG_NONE, &anonymous, N_("Use an anonymous user when authenticating"), NULL },
/* Translator: List here is a verb as in 'List all mounts' */
{ "list", 'l', 0, G_OPTION_ARG_NONE, &mount_list, N_("List"), NULL},
{ "monitor", 'o', 0, G_OPTION_ARG_NONE, &mount_monitor, N_("Monitor events"), NULL},
{ "detail", 'i', 0, G_OPTION_ARG_NONE, &extra_detail, N_("Show extra information"), NULL},
{ "tcrypt-pim", 0, 0, G_OPTION_ARG_INT, &tcrypt_pim, N_("The numeric PIM when unlocking a VeraCrypt volume"), N_("PIM")},
{ "tcrypt-hidden", 0, 0, G_OPTION_ARG_NONE, &tcrypt_hidden, N_("Mount a TCRYPT hidden volume"), NULL},
{ "tcrypt-system", 0, 0, G_OPTION_ARG_NONE, &tcrypt_system, N_("Mount a TCRYPT system volume"), NULL},
{ NULL }
};
static char *
prompt_for (const char *prompt, const char *default_value, gboolean echo)
{
#ifdef HAVE_TERMIOS_H
struct termios term_attr;
int old_flags;
gboolean restore_flags;
#endif
char data[256];
int len;
if (default_value && *default_value != 0)
g_print ("%s [%s]: ", prompt, default_value);
else
g_print ("%s: ", prompt);
data[0] = 0;
#ifdef HAVE_TERMIOS_H
restore_flags = FALSE;
if (!echo && tcgetattr (STDIN_FILENO, &term_attr) == 0)
{
old_flags = term_attr.c_lflag;
term_attr.c_lflag &= ~ECHO;
restore_flags = TRUE;
if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_attr) != 0)
g_print ("Warning! Password will be echoed");
}
#endif
fgets(data, sizeof (data), stdin);
#ifdef HAVE_TERMIOS_H
if (restore_flags)
{
term_attr.c_lflag = old_flags;
tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_attr);
}
#endif
len = strlen (data);
if (len == 0)
{
g_print ("\n");
return NULL;
}
if (data[len-1] == '\n')
data[len-1] = 0;
if (!echo)
g_print ("\n");
if (*data == 0 && default_value)
return g_strdup (default_value);
return g_strdup (data);
}
static void
ask_password_cb (GMountOperation *op,
const char *message,
const char *default_user,
const char *default_domain,
GAskPasswordFlags flags)
{
if ((flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED) && anonymous)
{
g_mount_operation_set_anonymous (op, TRUE);
}
else
{
char *s;
g_print ("%s\n", message);
if (flags & G_ASK_PASSWORD_NEED_USERNAME)
{
s = prompt_for ("User", default_user, TRUE);
if (!s)
goto error;
g_mount_operation_set_username (op, s);
g_free (s);
}
if (flags & G_ASK_PASSWORD_NEED_DOMAIN)
{
s = prompt_for ("Domain", default_domain, TRUE);
if (!s)
goto error;
g_mount_operation_set_domain (op, s);
g_free (s);
}
if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
{
s = prompt_for ("Password", NULL, FALSE);
if (!s)
goto error;
g_mount_operation_set_password (op, s);
g_free (s);
}
}
if (flags & G_ASK_PASSWORD_TCRYPT)
{
if (tcrypt_pim)
g_mount_operation_set_pim (op, tcrypt_pim);
if (tcrypt_hidden)
g_mount_operation_set_is_tcrypt_hidden_volume (op, TRUE);
if (tcrypt_system)
g_mount_operation_set_is_tcrypt_system_volume (op, TRUE);
}
/* Only try anonymous access once. */
if (anonymous &&
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ASKED)
{
g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_ABORTED));
g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
}
else
{
g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_ASKED));
g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
}
return;
error:
g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
}
static void
ask_question_cb (GMountOperation *op,
char *message,
char **choices,
gpointer user_data)
{
char **ptr = choices;
char *s;
int i, choice;
g_print ("%s\n", message);
i = 1;
while (*ptr)
{
g_print ("[%d] %s\n", i, *ptr++);
i++;
}
s = prompt_for ("Choice", NULL, TRUE);
if (!s)
goto error;
choice = atoi (s);
if (choice > 0 && choice < i)
{
g_mount_operation_set_choice (op, choice - 1);
g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
}
g_free (s);
return;
error:
g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
}
static void
mount_mountable_done_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GFile *target;
GError *error = NULL;
GMountOperation *op = user_data;
target = g_file_mount_mountable_finish (G_FILE (object), res, &error);
if (target == NULL)
{
success = FALSE;
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ABORTED)
print_file_error (G_FILE (object), _("Anonymous access denied"));
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
print_file_error (G_FILE (object), error->message);
g_error_free (error);
}
else
g_object_unref (target);
g_object_unref (op);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static void
mount_done_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
gboolean succeeded;
GError *error = NULL;
GMountOperation *op = user_data;
succeeded = g_file_mount_enclosing_volume_finish (G_FILE (object), res, &error);
if (!succeeded)
{
success = FALSE;
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ABORTED)
print_file_error (G_FILE (object), _("Anonymous access denied"));
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED))
print_file_error (G_FILE (object), error->message);
g_error_free (error);
}
g_object_unref (op);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static GMountOperation *
new_mount_op (void)
{
GMountOperation *op;
op = g_mount_operation_new ();
g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_NONE));
g_signal_connect (op, "ask_password", G_CALLBACK (ask_password_cb), NULL);
g_signal_connect (op, "ask_question", G_CALLBACK (ask_question_cb), NULL);
/* TODO: we *should* also connect to the "aborted" signal but since the
* main thread is blocked handling input we won't get that signal anyway...
*/
return op;
}
static void
mount (GFile *file)
{
GMountOperation *op;
if (file == NULL)
return;
op = new_mount_op ();
if (mount_mountable)
g_file_mount_mountable (file, 0, op, NULL, mount_mountable_done_cb, op);
else
g_file_mount_enclosing_volume (file, 0, op, NULL, mount_done_cb, op);
outstanding_mounts++;
}
static void
unmount_done_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
gboolean succeeded;
GError *error = NULL;
GFile *file = G_FILE (user_data);
succeeded = g_mount_unmount_with_operation_finish (G_MOUNT (object), res, &error);
g_object_unref (G_MOUNT (object));
if (!succeeded)
{
print_file_error (file, error->message);
success = FALSE;
g_error_free (error);
}
g_object_unref (file);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static void
unmount (GFile *file)
{
GMount *mount;
GError *error = NULL;
GMountOperation *mount_op;
GMountUnmountFlags flags;
if (file == NULL)
return;
mount = g_file_find_enclosing_mount (file, NULL, &error);
if (mount == NULL)
{
print_file_error (file, error->message);
success = FALSE;
g_error_free (error);
return;
}
mount_op = new_mount_op ();
flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE;
g_mount_unmount_with_operation (mount, flags, mount_op, NULL, unmount_done_cb, g_object_ref (file));
g_object_unref (mount_op);
outstanding_mounts++;
}
static void
eject_done_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
gboolean succeeded;
GError *error = NULL;
GFile *file = G_FILE (user_data);
succeeded = g_mount_eject_with_operation_finish (G_MOUNT (object), res, &error);
g_object_unref (G_MOUNT (object));
if (!succeeded)
{
print_file_error (file, error->message);
success = FALSE;
g_error_free (error);
}
g_object_unref (file);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static void
eject (GFile *file)
{
GMount *mount;
GError *error = NULL;
GMountOperation *mount_op;
GMountUnmountFlags flags;
if (file == NULL)
return;
mount = g_file_find_enclosing_mount (file, NULL, &error);
if (mount == NULL)
{
print_file_error (file, error->message);
success = FALSE;
g_error_free (error);
return;
}
mount_op = new_mount_op ();
flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE;
g_mount_eject_with_operation (mount, flags, mount_op, NULL, eject_done_cb, g_object_ref (file));
g_object_unref (mount_op);
outstanding_mounts++;
}
static void
stop_with_device_file_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
gchar *device_path = user_data;
if (!g_drive_stop_finish (G_DRIVE (object), res, &error))
{
print_error ("%s: %s", device_path, error->message);
g_error_free (error);
success = FALSE;
}
g_free (device_path);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static void
stop_with_device_file (const char *device_file)
{
GList *drives;
GList *l;
drives = g_volume_monitor_get_connected_drives (volume_monitor);
for (l = drives; l != NULL; l = l->next)
{
GDrive *drive = G_DRIVE (l->data);
gchar *id;
id = g_drive_get_identifier (drive, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
if (g_strcmp0 (id, device_file) == 0)
{
GMountOperation *op;
GMountUnmountFlags flags;
op = new_mount_op ();
flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE;
g_drive_stop (drive,
flags,
op,
NULL,
stop_with_device_file_cb,
g_steal_pointer (&id));
g_object_unref (op);
outstanding_mounts++;
}
g_free (id);
}
g_list_free_full (drives, g_object_unref);
if (outstanding_mounts == 0)
{
print_error ("%s: %s", device_file, _("No drive for device file"));
success = FALSE;
}
}
static gboolean
iterate_gmain_timeout_function (gpointer data)
{
g_main_loop_quit (main_loop);
return FALSE;
}
static void
iterate_gmain(void)
{
g_timeout_add (500, iterate_gmain_timeout_function, NULL);
g_main_loop_run (main_loop);
}
static void
show_themed_icon_names (GThemedIcon *icon, gboolean symbolic, int indent)
{
char **names;
char **iter;
g_print ("%*s%sthemed icons:", indent, " ", symbolic ? "symbolic " : "");
names = NULL;
g_object_get (icon, "names", &names, NULL);
for (iter = names; *iter; iter++)
g_print (" [%s]", *iter);
g_print ("\n");
g_strfreev (names);
}
/* don't copy-paste this code */
static char *
get_type_name (gpointer object)
{
const char *type_name;
char *ret;
type_name = g_type_name (G_TYPE_FROM_INSTANCE (object));
if (strcmp ("GProxyDrive", type_name) == 0)
{
ret = g_strdup_printf ("%s (%s)",
type_name,
(const char *) g_object_get_data (G_OBJECT (object),
"g-proxy-drive-volume-monitor-name"));
}
else if (strcmp ("GProxyVolume", type_name) == 0)
{
ret = g_strdup_printf ("%s (%s)",
type_name,
(const char *) g_object_get_data (G_OBJECT (object),
"g-proxy-volume-volume-monitor-name"));
}
else if (strcmp ("GProxyMount", type_name) == 0)
{
ret = g_strdup_printf ("%s (%s)",
type_name,
(const char *) g_object_get_data (G_OBJECT (object),
"g-proxy-mount-volume-monitor-name"));
}
else if (strcmp ("GProxyShadowMount", type_name) == 0)
{
ret = g_strdup_printf ("%s (%s)",
type_name,
(const char *) g_object_get_data (G_OBJECT (object),
"g-proxy-shadow-mount-volume-monitor-name"));
}
else
{
ret = g_strdup (type_name);
}
return ret;
}
static void
list_mounts (GList *mounts,
int indent,
gboolean only_with_no_volume)
{
GList *l;
int c;
GMount *mount;
GVolume *volume;
char *name, *uuid, *uri;
GFile *root, *default_location;
GIcon *icon;
char **x_content_types;
char *type_name;
const gchar *sort_key;
for (c = 0, l = mounts; l != NULL; l = l->next, c++)
{
mount = (GMount *) l->data;
if (only_with_no_volume)
{
volume = g_mount_get_volume (mount);
if (volume != NULL)
{
g_object_unref (volume);
continue;
}
}
name = g_mount_get_name (mount);
root = g_mount_get_root (mount);
uri = g_file_get_uri (root);
g_print ("%*sMount(%d): %s -> %s\n", indent, "", c, name, uri);
type_name = get_type_name (mount);
g_print ("%*sType: %s\n", indent+2, "", type_name);
g_free (type_name);
if (extra_detail)
{
uuid = g_mount_get_uuid (mount);
if (uuid)
g_print ("%*suuid=%s\n", indent + 2, "", uuid);
default_location = g_mount_get_default_location (mount);
if (default_location)
{
char *loc_uri = g_file_get_uri (default_location);
g_print ("%*sdefault_location=%s\n", indent + 2, "", loc_uri);
g_free (loc_uri);
g_object_unref (default_location);
}
icon = g_mount_get_icon (mount);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2);
g_object_unref (icon);
}
icon = g_mount_get_symbolic_icon (mount);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2);
g_object_unref (icon);
}
x_content_types = g_mount_guess_content_type_sync (mount, FALSE, NULL, NULL);
if (x_content_types != NULL && g_strv_length (x_content_types) > 0)
{
int n;
g_print ("%*sx_content_types:", indent + 2, "");
for (n = 0; x_content_types[n] != NULL; n++)
g_print (" %s", x_content_types[n]);
g_print ("\n");
}
g_strfreev (x_content_types);
g_print ("%*scan_unmount=%d\n", indent + 2, "", g_mount_can_unmount (mount));
g_print ("%*scan_eject=%d\n", indent + 2, "", g_mount_can_eject (mount));
g_print ("%*sis_shadowed=%d\n", indent + 2, "", g_mount_is_shadowed (mount));
sort_key = g_mount_get_sort_key (mount);
if (sort_key != NULL)
g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key);
g_free (uuid);
}
g_object_unref (root);
g_free (name);
g_free (uri);
}
}
static void
list_volumes (GList *volumes,
int indent,
gboolean only_with_no_drive)
{
GList *l, *mounts;
int c, i;
GMount *mount;
GVolume *volume;
GDrive *drive;
char *name;
char *uuid;
GFile *activation_root;
char **ids;
GIcon *icon;
char *type_name;
const gchar *sort_key;
for (c = 0, l = volumes; l != NULL; l = l->next, c++)
{
volume = (GVolume *) l->data;
if (only_with_no_drive)
{
drive = g_volume_get_drive (volume);
if (drive != NULL)
{
g_object_unref (drive);
continue;
}
}
name = g_volume_get_name (volume);
g_print ("%*sVolume(%d): %s\n", indent, "", c, name);
g_free (name);
type_name = get_type_name (volume);
g_print ("%*sType: %s\n", indent+2, "", type_name);
g_free (type_name);
if (extra_detail)
{
ids = g_volume_enumerate_identifiers (volume);
if (ids && ids[0] != NULL)
{
g_print ("%*sids:\n", indent+2, "");
for (i = 0; ids[i] != NULL; i++)
{
char *id = g_volume_get_identifier (volume,
ids[i]);
g_print ("%*s %s: '%s'\n", indent+2, "", ids[i], id);
g_free (id);
}
}
g_strfreev (ids);
uuid = g_volume_get_uuid (volume);
if (uuid)
g_print ("%*suuid=%s\n", indent + 2, "", uuid);
activation_root = g_volume_get_activation_root (volume);
if (activation_root)
{
char *uri;
uri = g_file_get_uri (activation_root);
g_print ("%*sactivation_root=%s\n", indent + 2, "", uri);
g_free (uri);
g_object_unref (activation_root);
}
icon = g_volume_get_icon (volume);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2);
g_object_unref (icon);
}
icon = g_volume_get_symbolic_icon (volume);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2);
g_object_unref (icon);
}
g_print ("%*scan_mount=%d\n", indent + 2, "", g_volume_can_mount (volume));
g_print ("%*scan_eject=%d\n", indent + 2, "", g_volume_can_eject (volume));
g_print ("%*sshould_automount=%d\n", indent + 2, "", g_volume_should_automount (volume));
sort_key = g_volume_get_sort_key (volume);
if (sort_key != NULL)
g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key);
g_free (uuid);
}
mount = g_volume_get_mount (volume);
if (mount)
{
mounts = g_list_prepend (NULL, mount);
list_mounts (mounts, indent + 2, FALSE);
g_list_free (mounts);
g_object_unref (mount);
}
}
}
static void
list_drives (GList *drives,
int indent)
{
GList *volumes, *l;
int c, i;
GDrive *drive;
char *name;
char **ids;
GIcon *icon;
char *type_name;
const gchar *sort_key;
for (c = 0, l = drives; l != NULL; l = l->next, c++)
{
drive = (GDrive *) l->data;
name = g_drive_get_name (drive);
g_print ("%*sDrive(%d): %s\n", indent, "", c, name);
g_free (name);
type_name = get_type_name (drive);
g_print ("%*sType: %s\n", indent+2, "", type_name);
g_free (type_name);
if (extra_detail)
{
GEnumValue *enum_value;
gpointer klass;
ids = g_drive_enumerate_identifiers (drive);
if (ids && ids[0] != NULL)
{
g_print ("%*sids:\n", indent+2, "");
for (i = 0; ids[i] != NULL; i++)
{
char *id = g_drive_get_identifier (drive,
ids[i]);
g_print ("%*s %s: '%s'\n", indent+2, "", ids[i], id);
g_free (id);
}
}
g_strfreev (ids);
icon = g_drive_get_icon (drive);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2);
g_object_unref (icon);
}
icon = g_drive_get_symbolic_icon (drive);
if (icon)
{
if (G_IS_THEMED_ICON (icon))
show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2);
g_object_unref (icon);
}
g_print ("%*sis_removable=%d\n", indent + 2, "", g_drive_is_removable (drive));
g_print ("%*sis_media_removable=%d\n", indent + 2, "", g_drive_is_media_removable (drive));
g_print ("%*shas_media=%d\n", indent + 2, "", g_drive_has_media (drive));
g_print ("%*sis_media_check_automatic=%d\n", indent + 2, "", g_drive_is_media_check_automatic (drive));
g_print ("%*scan_poll_for_media=%d\n", indent + 2, "", g_drive_can_poll_for_media (drive));
g_print ("%*scan_eject=%d\n", indent + 2, "", g_drive_can_eject (drive));
g_print ("%*scan_start=%d\n", indent + 2, "", g_drive_can_start (drive));
g_print ("%*scan_stop=%d\n", indent + 2, "", g_drive_can_stop (drive));
enum_value = NULL;
klass = g_type_class_ref (G_TYPE_DRIVE_START_STOP_TYPE);
if (klass != NULL)
{
enum_value = g_enum_get_value (klass, g_drive_get_start_stop_type (drive));
g_print ("%*sstart_stop_type=%s\n", indent + 2, "",
enum_value != NULL ? enum_value->value_nick : "UNKNOWN");
g_type_class_unref (klass);
}
sort_key = g_drive_get_sort_key (drive);
if (sort_key != NULL)
g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key);
}
volumes = g_drive_get_volumes (drive);
list_volumes (volumes, indent + 2, FALSE);
g_list_free_full (volumes, g_object_unref);
}
}
static void
list_monitor_items (void)
{
GList *drives, *volumes, *mounts;
/* populate gvfs network mounts */
iterate_gmain();
drives = g_volume_monitor_get_connected_drives (volume_monitor);
list_drives (drives, 0);
g_list_free_full (drives, g_object_unref);
volumes = g_volume_monitor_get_volumes (volume_monitor);
list_volumes (volumes, 0, TRUE);
g_list_free_full (volumes, g_object_unref);
mounts = g_volume_monitor_get_mounts (volume_monitor);
list_mounts (mounts, 0, TRUE);
g_list_free_full (mounts, g_object_unref);
}
static void
unmount_all_with_scheme (const char *scheme)
{
GList *mounts;
GList *l;
/* populate gvfs network mounts */
iterate_gmain();
mounts = g_volume_monitor_get_mounts (volume_monitor);
for (l = mounts; l != NULL; l = l->next) {
GMount *mount = G_MOUNT (l->data);
GFile *root;
root = g_mount_get_root (mount);
if (g_file_has_uri_scheme (root, scheme)) {
unmount (root);
}
g_object_unref (root);
}
g_list_free_full (mounts, g_object_unref);
}
static void
mount_with_device_file_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GVolume *volume;
gboolean succeeded;
GError *error = NULL;
gchar *id = (gchar *)user_data;
volume = G_VOLUME (object);
succeeded = g_volume_mount_finish (volume, res, &error);
if (!succeeded)
{
print_error ("%s: %s", id, error->message);
g_error_free (error);
success = FALSE;
}
else
{
GMount *mount;
GFile *root;
char *mount_path;
mount = g_volume_get_mount (volume);
root = g_mount_get_root (mount);
mount_path = g_file_get_path (root);
g_print (_("Mounted %s at %s\n"), id, mount_path);
g_object_unref (mount);
g_object_unref (root);
g_free (mount_path);
}
g_free (id);
outstanding_mounts--;
if (outstanding_mounts == 0)
g_main_loop_quit (main_loop);
}
static void
mount_with_id (const char *id)
{
GList *volumes;
GList *l;
volumes = g_volume_monitor_get_volumes (volume_monitor);
for (l = volumes; l != NULL; l = l->next)
{
GVolume *volume = G_VOLUME (l->data);
gchar *device;
gchar *uuid;
device = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
uuid = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UUID);
if (g_strcmp0 (device, id) == 0 || g_strcmp0 (uuid, id) == 0)
{
GMountOperation *op;
op = new_mount_op ();
g_volume_mount (volume,
G_MOUNT_MOUNT_NONE,
op,
NULL,
mount_with_device_file_cb,
g_strdup (id));
g_object_unref (op);
outstanding_mounts++;
}
g_free (device);
g_free (uuid);
}
g_list_free_full (volumes, g_object_unref);
if (outstanding_mounts == 0)
{
print_error ("%s: %s", id, _("No volume for given ID"));
success = FALSE;
}
}
static void
monitor_print_mount (GMount *mount)
{
if (extra_detail)
{
GList *l;
l = g_list_prepend (NULL, mount);
list_mounts (l, 2, FALSE);
g_list_free (l);
g_print ("\n");
}
}
static void
monitor_print_volume (GVolume *volume)
{
if (extra_detail)
{
GList *l;
l = g_list_prepend (NULL, volume);
list_volumes (l, 2, FALSE);
g_list_free (l);
g_print ("\n");
}
}
static void
monitor_print_drive (GDrive *drive)
{
if (extra_detail)
{
GList *l;
l = g_list_prepend (NULL, drive);
list_drives (l, 2);
g_list_free (l);
g_print ("\n");
}
}
static void
monitor_mount_added (GVolumeMonitor *volume_monitor, GMount *mount)
{
char *name;
name = g_mount_get_name (mount);
g_print ("Mount added: '%s'\n", name);
g_free (name);
monitor_print_mount (mount);
}
static void
monitor_mount_removed (GVolumeMonitor *volume_monitor, GMount *mount)
{
char *name;
name = g_mount_get_name (mount);
g_print ("Mount removed: '%s'\n", name);
g_free (name);
monitor_print_mount (mount);
}
static void
monitor_mount_changed (GVolumeMonitor *volume_monitor, GMount *mount)
{
char *name;
name = g_mount_get_name (mount);
g_print ("Mount changed: '%s'\n", name);
g_free (name);
monitor_print_mount (mount);
}
static void
monitor_mount_pre_unmount (GVolumeMonitor *volume_monitor, GMount *mount)
{
char *name;
name = g_mount_get_name (mount);
g_print ("Mount pre-unmount: '%s'\n", name);
g_free (name);
monitor_print_mount (mount);
}
static void
monitor_volume_added (GVolumeMonitor *volume_monitor, GVolume *volume)
{
char *name;
name = g_volume_get_name (volume);
g_print ("Volume added: '%s'\n", name);
g_free (name);
monitor_print_volume (volume);
}
static void
monitor_volume_removed (GVolumeMonitor *volume_monitor, GVolume *volume)
{
char *name;
name = g_volume_get_name (volume);
g_print ("Volume removed: '%s'\n", name);
g_free (name);
monitor_print_volume (volume);
}
static void
monitor_volume_changed (GVolumeMonitor *volume_monitor, GVolume *volume)
{
char *name;
name = g_volume_get_name (volume);
g_print ("Volume changed: '%s'\n", name);
g_free (name);
monitor_print_volume (volume);
}
static void
monitor_drive_connected (GVolumeMonitor *volume_monitor, GDrive *drive)
{
char *name;
name = g_drive_get_name (drive);
g_print ("Drive connected: '%s'\n", name);
g_free (name);
monitor_print_drive (drive);
}
static void
monitor_drive_disconnected (GVolumeMonitor *volume_monitor, GDrive *drive)
{
char *name;
name = g_drive_get_name (drive);
g_print ("Drive disconnected: '%s'\n", name);
g_free (name);
monitor_print_drive (drive);
}
static void
monitor_drive_changed (GVolumeMonitor *volume_monitor, GDrive *drive)
{
char *name;
name = g_drive_get_name (drive);
g_print ("Drive changed: '%s'\n", name);
g_free (name);
monitor_print_drive (drive);
}
static void
monitor_drive_eject_button (GVolumeMonitor *volume_monitor, GDrive *drive)
{
char *name;
name = g_drive_get_name (drive);
g_print ("Drive eject button: '%s'\n", name);
g_free (name);
}
static void
monitor (void)
{
g_signal_connect (volume_monitor, "mount-added", (GCallback) monitor_mount_added, NULL);
g_signal_connect (volume_monitor, "mount-removed", (GCallback) monitor_mount_removed, NULL);
g_signal_connect (volume_monitor, "mount-changed", (GCallback) monitor_mount_changed, NULL);
g_signal_connect (volume_monitor, "mount-pre-unmount", (GCallback) monitor_mount_pre_unmount, NULL);
g_signal_connect (volume_monitor, "volume-added", (GCallback) monitor_volume_added, NULL);
g_signal_connect (volume_monitor, "volume-removed", (GCallback) monitor_volume_removed, NULL);
g_signal_connect (volume_monitor, "volume-changed", (GCallback) monitor_volume_changed, NULL);
g_signal_connect (volume_monitor, "drive-connected", (GCallback) monitor_drive_connected, NULL);
g_signal_connect (volume_monitor, "drive-disconnected", (GCallback) monitor_drive_disconnected, NULL);
g_signal_connect (volume_monitor, "drive-changed", (GCallback) monitor_drive_changed, NULL);
g_signal_connect (volume_monitor, "drive-eject-button", (GCallback) monitor_drive_eject_button, NULL);
g_print ("Monitoring events. Press Ctrl+C to quit.\n");
g_main_loop_run (main_loop);
}
int
handle_mount (int argc, char *argv[], gboolean do_help)
{
GOptionContext *context;
gchar *param;
GError *error = NULL;
GFile *file;
int i;
g_set_prgname ("gio mount");
/* Translators: commandline placeholder */
param = g_strdup_printf ("[%s…]", _("LOCATION"));
context = g_option_context_new (param);
g_free (param);
g_option_context_set_help_enabled (context, FALSE);
g_option_context_set_summary (context, _("Mount or unmount the locations."));
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
if (do_help)
{
show_help (context, NULL);
g_option_context_free (context);
return 0;
}
if (!g_option_context_parse (context, &argc, &argv, &error))
{
show_help (context, error->message);
g_error_free (error);
g_option_context_free (context);
return 1;
}
main_loop = g_main_loop_new (NULL, FALSE);
volume_monitor = g_volume_monitor_get ();
if (mount_list)
list_monitor_items ();
else if (mount_id != NULL)
mount_with_id (mount_id);
else if (stop_device_file)
stop_with_device_file (stop_device_file);
else if (unmount_scheme != NULL)
unmount_all_with_scheme (unmount_scheme);
else if (mount_monitor)
monitor ();
else if (argc > 1)
{
for (i = 1; i < argc; i++)
{
file = g_file_new_for_commandline_arg (argv[i]);
if (mount_unmount)
unmount (file);
else if (mount_eject)
eject (file);
else
mount (file);
g_object_unref (file);
}
}
else
{
show_help (context, _("No locations given"));
g_option_context_free (context);
g_object_unref (volume_monitor);
return 1;
}
g_option_context_free (context);
if (outstanding_mounts > 0)
g_main_loop_run (main_loop);
g_object_unref (volume_monitor);
return success ? 0 : 2;
}