Commit e15873e3 authored by Christian Kellner's avatar Christian Kellner
Browse files

daemon: first step towards a dbus daemon

All the old sources (lib, and tools) are not built anymore, but
still kept around for now.
parent f8ae3b69
/*
* Copyright © 2017 Red Hat, Inc
*
* This program 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/>.
*
* Authors:
* Christian J. Kellner <christian@kellner.me>
*/
#include "config.h"
#include "bolt-dbus.h"
#include "bolt-manager.h"
#include <gio/gio.h>
#include <locale.h>
#include <stdlib.h>
#define ANSI_NORMAL "\x1B[0m"
#define ANSI_RED "\x1B[0;31m"
#define ANSI_GREEN "\x1B[0;32m"
#define ANSI_YELLOW "\x1B[0;33m"
#define ANSI_BLUE "\x1B[0;34m"
#define ANSI_HIGHLIGHT_BLACK "\x1B[0;1;30m"
#define ANSI_HIGHLIGHT_RED "\x1B[0;1;31m"
/* globals */
static BoltManager *manager = NULL;
static GMainLoop *main_loop = NULL;
static guint name_owner_id = 0;
static const char *
ansi_color (const char *c)
{
return c;
}
#define TIME_MAXFMT 255
static void
log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
const char *normal = ansi_color (ANSI_NORMAL);
const char *fg = normal;
gchar the_time[TIME_MAXFMT];
time_t now;
struct tm *tm;
time (&now);
tm = localtime (&now);
if (tm && strftime (the_time, sizeof (the_time), "%T", tm) > 0)
{
const char *gray = ansi_color (ANSI_HIGHLIGHT_BLACK);
g_printerr ("%s%s%s ", gray, the_time, normal);
}
if (log_level == G_LOG_LEVEL_CRITICAL ||
log_level == G_LOG_LEVEL_ERROR)
fg = ansi_color (ANSI_RED);
else if (log_level == G_LOG_LEVEL_WARNING)
fg = ansi_color (ANSI_YELLOW);
else if (log_level == G_LOG_LEVEL_INFO)
fg = ansi_color (ANSI_BLUE);
g_printerr ("%s%s%s\n", fg, message, normal);
}
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
BoltManager *mgr = BOLT_MANAGER (user_data);
g_autoptr(GError) error = NULL;
g_debug ("Got the bus [%s]", name);
if (!bolt_manager_export (mgr, connection, &error))
g_warning ("error: %s", error->message);
}
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_debug ("Got the name");
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
g_debug ("Lost the name. Shutting down...");
g_clear_object (&manager);
g_bus_unown_name (name_owner_id);
g_main_loop_quit (main_loop);
}
int
main (int argc, char **argv)
{
GOptionContext *context;
gboolean replace = FALSE;
gboolean verbose = FALSE;
gboolean show_version = FALSE;
GBusNameOwnerFlags flags;
g_autoptr(GError) error = NULL;
const GOptionEntry options[] = {
{ "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, "Replace old daemon.", NULL },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Enable debug output.", NULL },
{ "version", 0, 0, G_OPTION_ARG_NONE, &show_version, "Print daemon version.", NULL},
{ NULL }
};
setlocale (LC_ALL, "");
g_setenv ("GIO_USE_VFS", "local", TRUE);
g_set_prgname (argv[0]);
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, log_handler, NULL);
context = g_option_context_new ("");
g_option_context_set_summary (context, "Thunderbolt system daemon");
g_option_context_add_main_entries (context, options, PACKAGE_NAME);
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_printerr ("%s: %s", g_get_application_name (), error->message);
g_printerr ("\n");
g_printerr ("Try \"%s --help\" for more information.",
g_get_prgname ());
g_printerr ("\n");
g_option_context_free (context);
return EXIT_FAILURE;
}
if (show_version)
{
g_print (PACKAGE_NAME " " PACKAGE_VERSION "\n");
return EXIT_SUCCESS;
}
if (verbose)
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, log_handler, NULL);
g_debug (PACKAGE_NAME " " PACKAGE_VERSION " starting up.");
/* */
manager = g_initable_new (BOLT_TYPE_MANAGER,
NULL, &error,
NULL);
if (manager == NULL)
{
g_printerr ("Could not create manager: %s", error->message);
return EXIT_FAILURE;
}
flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
if (replace)
flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
BOLT_DBUS_NAME,
flags,
on_bus_acquired,
on_name_acquired,
on_name_lost,
manager,
NULL);
main_loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (main_loop);
/* When all is said and done, more is said then done. */
g_main_loop_unref (main_loop);
return EXIT_SUCCESS;
}
/*
* Copyright © 2017 Red Hat, Inc
*
* This program 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/>.
*
* Authors:
* Christian J. Kellner <christian@kellner.me>
*/
#include "config.h"
#include "bolt-device.h"
#include "bolt-error.h"
#include <libudev.h>
struct _BoltDevice
{
BoltDBusDeviceSkeleton object;
char *uid;
};
enum {
PROP_0,
PROP_UID,
PROP_LAST
};
G_DEFINE_TYPE (BoltDevice,
bolt_device,
BOLT_DBUS_TYPE_DEVICE_SKELETON)
static void
bolt_device_finalize (GObject *object)
{
BoltDevice *dev = BOLT_DEVICE (object);
g_free (dev->uid);
G_OBJECT_CLASS (bolt_device_parent_class)->finalize (object);
}
static void
bolt_device_init (BoltDevice *mgr)
{
}
static void
bolt_device_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BoltDevice *dev = BOLT_DEVICE (object);
switch (prop_id)
{
case PROP_UID:
g_value_set_string (value, dev->uid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bolt_device_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BoltDevice *dev = BOLT_DEVICE (object);
switch (prop_id)
{
case PROP_UID:
dev->uid = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bolt_device_class_init (BoltDeviceClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = bolt_device_finalize;
gobject_class->get_property = bolt_device_get_property;
gobject_class->set_property = bolt_device_set_property;
g_object_class_override_property (gobject_class,
PROP_UID,
"uid");
}
/* public methods */
BoltDevice *
bolt_device_new_for_udev (BoltManager *mgr,
struct udev_device *udev,
GError **error)
{
BoltDevice *dev;
const char *uid;
uid = udev_device_get_sysattr_value (udev, "unique_id");
if (uid == NULL)
{
g_set_error_literal (error,
BOLT_ERROR, BOLT_ERROR_UDEV,
"failed to read unique_id");
return NULL;
}
dev = g_object_new (BOLT_TYPE_DEVICE,
"uid", uid,
NULL);
return dev;
}
gboolean
bolt_device_export (BoltDevice *device,
GDBusConnection *connection,
GError **error)
{
g_autofree char *path = NULL;
path = g_strdup_printf ("/org/freedesktop/Bolt/devices/%s", device->uid);
g_strdelimit (path, "-", '_');
g_debug ("Exporting device at: %s", path);
return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (device),
connection,
path,
error);
}
void
bolt_device_unexport (BoltDevice *device)
{
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (device));
}
/*
* Copyright © 2017 Red Hat, Inc
*
* This program 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/>.
*
* Authors:
* Christian J. Kellner <christian@kellner.me>
*/
#pragma once
#include "bolt-gdbus.h"
#include "bolt-manager.h"
/* forward declaration */
struct udev_device;
G_BEGIN_DECLS
#define BOLT_TYPE_DEVICE bolt_device_get_type ()
G_DECLARE_FINAL_TYPE (BoltDevice, bolt_device, BOLT, DEVICE, BoltDBusDeviceSkeleton);
BoltDevice * bolt_device_new_for_udev (BoltManager *manager,
struct udev_device *udev,
GError **error);
gboolean bolt_device_export (BoltDevice *device,
GDBusConnection *connection,
GError **error);
void bolt_device_unexport (BoltDevice *device);
G_END_DECLS
/*
* Copyright © 2017 Red Hat, Inc
*
* This program 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/>.
*
* Authors:
* Christian J. Kellner <christian@kellner.me>
*/
#include "config.h"
#include "bolt-device.h"
#include "bolt-error.h"
#include "bolt-manager.h"
#include <libudev.h>
typedef struct udev_monitor udev_monitor;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (udev_monitor, udev_monitor_unref);
typedef struct udev_device udev_device;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (udev_device, udev_device_unref);
static void bolt_manager_initable_iface_init (GInitableIface *iface);
static gboolean bolt_manager_initialize (GInitable *initable,
GCancellable *cancellable,
GError **error);
struct _BoltManager
{
BoltDBusManagerSkeleton object;
struct udev *udev;
struct udev_monitor *udev_monitor;
struct udev_monitor *kernel_monitor;
GSource *udev_source;
GSource *kernel_source;
GPtrArray *devices;
};
enum {
PROP_0,
PROP_VERSION,
PROP_LAST
};
G_DEFINE_TYPE_WITH_CODE (BoltManager,
bolt_manager,
BOLT_DBUS_TYPE_MANAGER_SKELETON,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
bolt_manager_initable_iface_init));
static void
bolt_manager_finalize (GObject *object)
{
BoltManager *mgr = BOLT_MANAGER (object);
g_ptr_array_free (mgr->devices, TRUE);
G_OBJECT_CLASS (bolt_manager_parent_class)->finalize (object);
}
static void
bolt_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_VERSION:
g_value_set_string (value, PACKAGE_VERSION);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bolt_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_VERSION:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bolt_manager_init (BoltManager *mgr)
{
mgr->devices = g_ptr_array_new_with_free_func (g_object_unref);
}
static void
bolt_manager_class_init (BoltManagerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = bolt_manager_finalize;
gobject_class->get_property = bolt_manager_get_property;
gobject_class->set_property = bolt_manager_set_property;
g_object_class_override_property (gobject_class,
PROP_VERSION,
"version");
}
static void
bolt_manager_initable_iface_init (GInitableIface *iface)
{
iface->init = bolt_manager_initialize;
}
static gboolean
setup_monitor (BoltManager *mgr,
const char *name,
GSourceFunc callback,
udev_monitor **monitor_out,
GSource **watch_out,
GError **error)
{
g_autoptr(udev_monitor) monitor = NULL;
g_autoptr(GIOChannel) channel = NULL;
GSource *watch;
int fd;
int res;
monitor = udev_monitor_new_from_netlink (mgr->udev, name);
if (monitor == NULL)
{
g_set_error_literal (error, BOLT_ERROR, BOLT_ERROR_UDEV,
"udev: could not create monitor");
return FALSE;
}
udev_monitor_set_receive_buffer_size (monitor, 128 * 1024 * 1024);
res = udev_monitor_filter_add_match_subsystem_devtype (monitor, "thunderbolt", NULL);
if (res < 0)
{
g_set_error_literal (error, BOLT_ERROR, BOLT_ERROR_UDEV,
"udev: could not add match for 'thunderbolt' to monitor");
return FALSE;
}
res = udev_monitor_enable_receiving (monitor);
if (res < 0)
{
g_set_error_literal (error, BOLT_ERROR, BOLT_ERROR_UDEV,
"udev: could not enable monitoring");
return FALSE;
}
fd = udev_monitor_get_fd (monitor);
if (fd < 0)
{
g_set_error_literal (error, BOLT_ERROR, BOLT_ERROR_UDEV,
"udev: could not obtain fd for monitoring");
return FALSE;
}
channel = g_io_channel_unix_new (fd);
watch = g_io_create_watch (channel, G_IO_IN);
g_source_set_callback (watch, callback, mgr, NULL);
g_source_attach (watch, g_main_context_get_thread_default ());
*monitor_out = udev_monitor_ref (monitor);
*watch_out = watch;
return TRUE;
}
static gboolean
handle_uevent_kernel (GIOChannel *source,
GIOCondition condition,
gpointer user_data)
{
BoltManager *mgr = BOLT_MANAGER (user_data);
g_autoptr(udev_device) device = NULL;
const char *action;
device = udev_monitor_receive_device (mgr->kernel_monitor);
if (device == NULL)
return G_SOURCE_CONTINUE;
action = udev_device_get_action (device);
if (action == NULL)