mirror of https://gitee.com/openkylin/gvfs.git
411 lines
10 KiB
C
411 lines
10 KiB
C
/* GIO - GLib Input, Output and Streaming Library
|
|
*
|
|
* Copyright (C) 2006-2007 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 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, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
* Author: Alexander Larsson <alexl@redhat.com>
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <locale.h>
|
|
|
|
#include <glib.h>
|
|
#include "daemon-main.h"
|
|
#include <glib/gi18n.h>
|
|
#include <gvfsdaemon.h>
|
|
#include <gvfsbackend.h>
|
|
#include <gvfsdbus.h>
|
|
#include <gvfsutils.h>
|
|
|
|
static char *spawner_id = NULL;
|
|
static char *spawner_path = NULL;
|
|
|
|
static gboolean already_acquired = FALSE;
|
|
static int process_result = 0;
|
|
|
|
static GMainLoop *loop;
|
|
|
|
|
|
static void
|
|
log_debug (const gchar *log_domain,
|
|
GLogLevelFlags log_level,
|
|
const gchar *message,
|
|
gpointer user_data)
|
|
{
|
|
if (gvfs_get_debug ())
|
|
g_print ("%s: %s", (const gchar *)user_data, message);
|
|
}
|
|
|
|
void
|
|
daemon_init (void)
|
|
{
|
|
GDBusConnection *conn;
|
|
GError *error;
|
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
bindtextdomain (GETTEXT_PACKAGE, GVFS_LOCALEDIR);
|
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
|
textdomain (GETTEXT_PACKAGE);
|
|
|
|
g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, log_debug, G_STRINGIFY (DEFAULT_BACKEND_TYPE));
|
|
|
|
gvfs_setup_debug_handler ();
|
|
|
|
#ifdef SIGPIPE
|
|
/* Ignore SIGPIPE to avoid killing daemons on cancelled transfer *
|
|
* See https://bugzilla.gnome.org/show_bug.cgi?id=649041 *
|
|
*/
|
|
signal (SIGPIPE, SIG_IGN);
|
|
#endif
|
|
|
|
error = NULL;
|
|
conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
if (!conn)
|
|
{
|
|
g_printerr ("Error connecting to D-Bus: %s (%s, %d)\n",
|
|
error->message, g_quark_to_string (error->domain), error->code);
|
|
g_error_free (error);
|
|
exit (1);
|
|
}
|
|
g_object_unref (conn);
|
|
}
|
|
|
|
void
|
|
daemon_setup (void)
|
|
{
|
|
char *name, *up;
|
|
|
|
up = g_ascii_strup (G_STRINGIFY (DEFAULT_BACKEND_TYPE), -1);
|
|
/* translators: This is the default daemon's application name,
|
|
* the %s is the type of the backend, like "FTP" */
|
|
name = g_strdup_printf (_("%s File System Service"), up);
|
|
g_set_application_name (name);
|
|
g_free (name);
|
|
g_free (up);
|
|
}
|
|
|
|
typedef struct {
|
|
GVfsDaemon *daemon;
|
|
GMountSpec *mount_spec;
|
|
int max_job_threads;
|
|
char *mountable_name;
|
|
} DaemonData;
|
|
|
|
typedef struct {
|
|
GDestroyNotify callback;
|
|
gpointer user_data;
|
|
} SpawnData;
|
|
|
|
static void
|
|
spawned_failed_cb (gpointer user_data)
|
|
{
|
|
process_result = 1;
|
|
g_main_loop_quit (loop);
|
|
}
|
|
|
|
static void
|
|
spawned_succeeded_cb (gpointer user_data)
|
|
{
|
|
DaemonData *data = user_data;
|
|
GMountSource *mount_source;
|
|
|
|
if (data->mount_spec)
|
|
{
|
|
mount_source = g_mount_source_new_dummy ();
|
|
g_vfs_daemon_initiate_mount (data->daemon, data->mount_spec, mount_source, FALSE, NULL, NULL);
|
|
g_mount_spec_unref (data->mount_spec);
|
|
g_object_unref (mount_source);
|
|
}
|
|
}
|
|
|
|
static void
|
|
call_spawned_cb (GVfsDBusSpawner *proxy,
|
|
GAsyncResult *res,
|
|
gpointer user_data)
|
|
{
|
|
GError *error = NULL;
|
|
SpawnData *data = user_data;
|
|
|
|
if (! gvfs_dbus_spawner_call_spawned_finish (proxy, res, &error))
|
|
{
|
|
g_dbus_error_strip_remote_error (error);
|
|
g_printerr ("call_spawned_cb: Error sending a message: %s (%s, %d)\n",
|
|
error->message, g_quark_to_string (error->domain), error->code);
|
|
g_error_free (error);
|
|
}
|
|
|
|
data->callback (data->user_data);
|
|
g_free (data);
|
|
}
|
|
|
|
static void
|
|
send_spawned (gboolean succeeded,
|
|
char *error_message,
|
|
guint32 error_code,
|
|
GDestroyNotify callback,
|
|
gpointer user_data)
|
|
{
|
|
GVfsDBusSpawner *proxy;
|
|
GError *error;
|
|
SpawnData *data;
|
|
|
|
if (error_message == NULL)
|
|
error_message = "";
|
|
|
|
if (spawner_id == NULL || spawner_path == NULL)
|
|
{
|
|
if (!succeeded)
|
|
{
|
|
g_printerr (_("Error: %s"), error_message);
|
|
g_printerr ("\n");
|
|
}
|
|
callback (user_data);
|
|
return;
|
|
}
|
|
|
|
error = NULL;
|
|
proxy = gvfs_dbus_spawner_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
|
spawner_id,
|
|
spawner_path,
|
|
NULL,
|
|
&error);
|
|
if (proxy == NULL)
|
|
{
|
|
g_printerr ("Error creating proxy: %s (%s, %d)\n",
|
|
error->message, g_quark_to_string (error->domain), error->code);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
|
|
data = g_new0 (SpawnData, 1);
|
|
data->callback = callback;
|
|
data->user_data = user_data;
|
|
|
|
gvfs_dbus_spawner_call_spawned (proxy,
|
|
succeeded,
|
|
error_message,
|
|
error_code,
|
|
NULL,
|
|
(GAsyncReadyCallback) call_spawned_cb,
|
|
data);
|
|
|
|
g_object_unref (proxy);
|
|
}
|
|
|
|
GMountSpec *
|
|
daemon_parse_args (int argc, char *argv[], const char *default_type)
|
|
{
|
|
GMountSpec *mount_spec;
|
|
|
|
if (argc > 1 && strcmp (argv[1], "--debug") == 0)
|
|
{
|
|
gvfs_set_debug (TRUE);
|
|
argc--;
|
|
argv++;
|
|
}
|
|
else if (g_getenv ("GVFS_DEBUG"))
|
|
{
|
|
gvfs_set_debug (TRUE);
|
|
}
|
|
|
|
mount_spec = NULL;
|
|
if (argc > 1 && strcmp (argv[1], "--spawner") == 0)
|
|
{
|
|
if (argc < 4)
|
|
{
|
|
g_printerr (_("Usage: %s --spawner dbus-id object_path"), argv[0]);
|
|
g_printerr ("\n");
|
|
exit (1);
|
|
}
|
|
|
|
spawner_id = argv[2];
|
|
spawner_path = argv[3];
|
|
}
|
|
else if (argc > 1 || default_type != NULL)
|
|
{
|
|
gboolean found_type;
|
|
int i;
|
|
|
|
mount_spec = g_mount_spec_new (default_type);
|
|
found_type = default_type != NULL;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
char *p;
|
|
char *key;
|
|
|
|
p = strchr (argv[i], '=');
|
|
if (p == NULL || p[1] == 0 || p == argv[i])
|
|
{
|
|
g_printerr (_("Usage: %s key=value key=value …"), argv[0]);
|
|
g_printerr ("\n");
|
|
exit (1);
|
|
}
|
|
|
|
key = g_strndup (argv[i], p - argv[i]);
|
|
if (strcmp (key, "type") == 0)
|
|
found_type = TRUE;
|
|
|
|
g_mount_spec_set (mount_spec, key, p+1);
|
|
g_debug ("setting '%s' to '%s'\n", key, p+1);
|
|
g_free (key);
|
|
}
|
|
|
|
if (!found_type)
|
|
{
|
|
g_printerr (_("No mount type specified"));
|
|
g_printerr ("\n");
|
|
g_printerr (_("Usage: %s key=value key=value …"), argv[0]);
|
|
g_printerr ("\n");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
return mount_spec;
|
|
}
|
|
|
|
static void
|
|
on_name_lost (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
DaemonData *data = user_data;
|
|
gchar *s;
|
|
|
|
if (connection == NULL)
|
|
{
|
|
g_printerr ("A connection to the bus can't be made\n");
|
|
process_result = 1;
|
|
}
|
|
else
|
|
{
|
|
if (already_acquired)
|
|
{
|
|
g_printerr ("Got NameLost, some other instance replaced us\n");
|
|
}
|
|
else
|
|
{
|
|
s = g_strdup_printf (_("mountpoint for %s already running"), data->mountable_name);
|
|
send_spawned (FALSE, s, G_IO_ERROR_ALREADY_MOUNTED, spawned_failed_cb, data);
|
|
g_free (s);
|
|
return;
|
|
}
|
|
}
|
|
g_main_loop_quit (loop);
|
|
}
|
|
|
|
static void
|
|
daemon_shutdown (GVfsDaemon *daemon,
|
|
GMainLoop *loop)
|
|
{
|
|
if (g_main_loop_is_running (loop))
|
|
g_main_loop_quit (loop);
|
|
}
|
|
|
|
static void
|
|
on_name_acquired (GDBusConnection *connection,
|
|
const gchar *name,
|
|
gpointer user_data)
|
|
{
|
|
DaemonData *data = user_data;
|
|
|
|
already_acquired = TRUE;
|
|
|
|
data->daemon = g_vfs_daemon_new (FALSE, FALSE);
|
|
if (data->daemon == NULL)
|
|
{
|
|
send_spawned (FALSE, _("error starting mount daemon"), G_IO_ERROR_FAILED, spawned_failed_cb, data);
|
|
return;
|
|
}
|
|
|
|
g_vfs_daemon_set_max_threads (data->daemon, data->max_job_threads);
|
|
g_signal_connect (data->daemon, "shutdown",
|
|
G_CALLBACK (daemon_shutdown), loop);
|
|
|
|
send_spawned (TRUE, NULL, 0, spawned_succeeded_cb, data);
|
|
}
|
|
|
|
void
|
|
daemon_main (int argc,
|
|
char *argv[],
|
|
int max_job_threads,
|
|
const char *default_type,
|
|
const char *mountable_name,
|
|
const char *first_type_name,
|
|
...)
|
|
{
|
|
va_list var_args;
|
|
const char *type;
|
|
guint name_owner_id;
|
|
DaemonData *data;
|
|
|
|
data = g_new0 (DaemonData, 1);
|
|
data->mountable_name = g_strdup (mountable_name);
|
|
data->max_job_threads = max_job_threads;
|
|
data->mount_spec = daemon_parse_args (argc, argv, default_type);
|
|
|
|
va_start (var_args, first_type_name);
|
|
|
|
type = first_type_name;
|
|
|
|
while (type != NULL)
|
|
{
|
|
GType backend_type = va_arg (var_args, GType);
|
|
|
|
g_vfs_register_backend (backend_type, type);
|
|
|
|
type = va_arg (var_args, char *);
|
|
}
|
|
va_end (var_args);
|
|
|
|
loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
name_owner_id = 0;
|
|
/* We want to own *some* name on the org.gtk.vfs.* namespace so that
|
|
filtering for us works from a sandbox */
|
|
if (data->mountable_name == NULL)
|
|
data->mountable_name = g_strdup_printf ("org.gtk.vfs.mountpoint_%d", getpid ());
|
|
|
|
name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
|
data->mountable_name,
|
|
G_BUS_NAME_OWNER_FLAGS_NONE,
|
|
NULL,
|
|
on_name_acquired,
|
|
on_name_lost,
|
|
data,
|
|
NULL);
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
g_clear_object (&data->daemon);
|
|
g_free (data->mountable_name);
|
|
g_free (data);
|
|
if (name_owner_id != 0)
|
|
g_bus_unown_name (name_owner_id);
|
|
if (loop != NULL)
|
|
g_main_loop_unref (loop);
|
|
|
|
if (process_result)
|
|
exit (process_result);
|
|
}
|