/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* Copyright (C) 2005 Carlos Garnacho * * 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 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Carlos Garnacho Parro */ #include #include #include #include "oobs-object.h" #include "oobs-object-private.h" #include "oobs-list.h" #include "oobs-list-private.h" #include "oobs-servicesconfig.h" #include "oobs-service.h" #include "utils.h" #define SERVICES_CONFIG_REMOTE_OBJECT "ServicesConfig" #define OOBS_SERVICES_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), OOBS_TYPE_SERVICES_CONFIG, OobsServicesConfigPrivate)) typedef struct _OobsServicesConfigPrivate OobsServicesConfigPrivate; struct _OobsServicesConfigPrivate { OobsList *services_list; GList *runlevels; OobsServicesRunlevel *default_runlevel; }; static void oobs_services_config_class_init (OobsServicesConfigClass *class); static void oobs_services_config_init (OobsServicesConfig *config); static void oobs_services_config_finalize (GObject *object); static void oobs_services_config_update (OobsObject *object); static void oobs_services_config_commit (OobsObject *object); G_DEFINE_TYPE (OobsServicesConfig, oobs_services_config, OOBS_TYPE_OBJECT); static void oobs_services_config_class_init (OobsServicesConfigClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); OobsObjectClass *oobs_object_class = OOBS_OBJECT_CLASS (class); object_class->finalize = oobs_services_config_finalize; oobs_object_class->commit = oobs_services_config_commit; oobs_object_class->update = oobs_services_config_update; g_type_class_add_private (object_class, sizeof (OobsServicesConfigPrivate)); } static void oobs_services_config_init (OobsServicesConfig *config) { OobsServicesConfigPrivate *priv; g_return_if_fail (OOBS_IS_SERVICES_CONFIG (config)); priv = OOBS_SERVICES_CONFIG_GET_PRIVATE (config); priv->services_list = _oobs_list_new (OOBS_TYPE_SERVICE); config->_priv = priv; } static void free_runlevel (OobsServicesRunlevel *runlevel) { g_free (runlevel->name); g_free (runlevel); } static void oobs_services_config_finalize (GObject *object) { OobsServicesConfigPrivate *priv; g_return_if_fail (OOBS_IS_SERVICES_CONFIG (object)); priv = OOBS_SERVICES_CONFIG (object)->_priv; if (priv) { if (priv->services_list) g_object_unref (priv->services_list); if (priv->runlevels) { g_list_foreach (priv->runlevels, (GFunc) free_runlevel, NULL); g_list_free (priv->runlevels); } priv->default_runlevel = NULL; } if (G_OBJECT_CLASS (oobs_services_config_parent_class)->finalize) (* G_OBJECT_CLASS (oobs_services_config_parent_class)->finalize) (object); } static gint runlevel_to_role (const gchar *runlevel) { if (strcmp (runlevel, "0") == 0) return OOBS_RUNLEVEL_HALT; else if (strcmp (runlevel, "1") == 0) return OOBS_RUNLEVEL_MONOUSER; else if (strcmp (runlevel, "6") == 0) return OOBS_RUNLEVEL_REBOOT; /* fallback value */ return OOBS_RUNLEVEL_MULTIUSER; } static void create_runlevels_list_from_dbus_reply (OobsObject *object, DBusMessage *reply, DBusMessageIter iter) { OobsServicesConfigPrivate *priv; OobsServicesRunlevel *runlevel; gchar *name; priv = OOBS_SERVICES_CONFIG (object)->_priv; while (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) { dbus_message_iter_get_basic (&iter, &name); runlevel = g_new0 (OobsServicesRunlevel, 1); runlevel->name = g_strdup (name); runlevel->role = runlevel_to_role (runlevel->name); priv->runlevels = g_list_prepend (priv->runlevels, runlevel); dbus_message_iter_next (&iter); } priv->runlevels = g_list_reverse (priv->runlevels); } static OobsServicesRunlevel* get_runlevel (OobsServicesConfig *config, const gchar *runlevel) { OobsServicesConfigPrivate *priv; OobsServicesRunlevel *rl; GList *list; priv = config->_priv; list = priv->runlevels; while (list) { rl = list->data; if (strcmp (rl->name, runlevel) == 0) return rl; list = list->next; } return NULL; } static void create_service_runlevels_from_dbus_reply (OobsServicesConfig *config, OobsService *service, DBusMessage *reply, DBusMessageIter struct_iter) { DBusMessageIter runlevel_iter; OobsServicesRunlevel *rl; OobsServiceStatus status; gchar *runlevel; gint priority; while (dbus_message_iter_get_arg_type (&struct_iter) == DBUS_TYPE_STRUCT) { dbus_message_iter_recurse (&struct_iter, &runlevel_iter); dbus_message_iter_get_basic (&runlevel_iter, &runlevel); dbus_message_iter_next (&runlevel_iter); dbus_message_iter_get_basic (&runlevel_iter, &status); dbus_message_iter_next (&runlevel_iter); dbus_message_iter_get_basic (&runlevel_iter, &priority); dbus_message_iter_next (&runlevel_iter); rl = get_runlevel (config, runlevel); if (rl) oobs_service_set_runlevel_configuration (service, rl, status, priority); dbus_message_iter_next (&struct_iter); } } static OobsService* create_service_from_dbus_reply (OobsServicesConfig *config, DBusMessage *reply, DBusMessageIter struct_iter) { GObject *service; DBusMessageIter iter, runlevels_iter; gchar *name; dbus_message_iter_recurse (&struct_iter, &iter); dbus_message_iter_get_basic (&iter, &name); dbus_message_iter_next (&iter); service = g_object_new (OOBS_TYPE_SERVICE, "name", name, NULL); dbus_message_iter_recurse (&iter, &runlevels_iter); create_service_runlevels_from_dbus_reply (config, OOBS_SERVICE (service), reply, runlevels_iter); return OOBS_SERVICE (service); } static void oobs_services_config_update (OobsObject *object) { OobsServicesConfigPrivate *priv; DBusMessage *reply; DBusMessageIter iter, elem_iter; OobsListIter list_iter; OobsService *service; gchar *default_runlevel; priv = OOBS_SERVICES_CONFIG (object)->_priv; reply = _oobs_object_get_dbus_message (object); _oobs_list_set_locked (priv->services_list, FALSE); /* First of all, free the previous config */ oobs_list_clear (priv->services_list); dbus_message_iter_init (reply, &iter); dbus_message_iter_recurse (&iter, &elem_iter); create_runlevels_list_from_dbus_reply (object, reply, elem_iter); dbus_message_iter_next (&iter); dbus_message_iter_get_basic (&iter, &default_runlevel); priv->default_runlevel = get_runlevel (OOBS_SERVICES_CONFIG (object), default_runlevel); dbus_message_iter_next (&iter); dbus_message_iter_recurse (&iter, &elem_iter); while (dbus_message_iter_get_arg_type (&elem_iter) == DBUS_TYPE_STRUCT) { service = create_service_from_dbus_reply (OOBS_SERVICES_CONFIG (object), reply, elem_iter); oobs_list_append (priv->services_list, &list_iter); oobs_list_set (priv->services_list, &list_iter, G_OBJECT (service)); g_object_unref (service); dbus_message_iter_next (&elem_iter); } _oobs_list_set_locked (priv->services_list, TRUE); } static void create_dbus_struct_from_service_runlevels (OobsService *service, GList *runlevels, DBusMessage *message, DBusMessageIter *iter) { DBusMessageIter runlevels_iter, struct_iter; OobsServicesRunlevel *runlevel; OobsServiceStatus status; gint priority; dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, &runlevels_iter); while (runlevels) { runlevel = runlevels->data; runlevels = runlevels->next; oobs_service_get_runlevel_configuration (service, runlevel, &status, &priority); if (status == OOBS_SERVICE_IGNORE) continue; dbus_message_iter_open_container (&runlevels_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter); utils_append_string (&struct_iter, runlevel->name); dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &status); dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &priority); dbus_message_iter_close_container (&runlevels_iter, &struct_iter); } dbus_message_iter_close_container (iter, &runlevels_iter); } static gboolean create_dbus_struct_from_service (OobsService *service, GList *runlevels, DBusMessage *message, DBusMessageIter *array_iter) { DBusMessageIter struct_iter; gchar *name; g_object_get (G_OBJECT (service), "name", &name, NULL); g_return_val_if_fail (name, FALSE); dbus_message_iter_open_container (array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter); utils_append_string (&struct_iter, name); create_dbus_struct_from_service_runlevels (service, runlevels, message, &struct_iter); dbus_message_iter_close_container (array_iter, &struct_iter); g_free (name); return TRUE; } static void oobs_services_config_commit (OobsObject *object) { OobsServicesConfigPrivate *priv; DBusMessage *message; DBusMessageIter iter, array_iter; OobsListIter list_iter; gboolean valid, correct; GObject *service; correct = TRUE; priv = OOBS_SERVICES_CONFIG (object)->_priv; message = _oobs_object_get_dbus_message (object); dbus_message_iter_init_append (message, &iter); /* FIXME: nothing inserted here, backends ignore this */ utils_create_dbus_array_from_string_list (NULL, message, &iter); /* FIXME: this is ignored by the backend too */ utils_append_string (&iter, NULL); dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_STRUCT_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_TYPE_INT32_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING DBUS_STRUCT_END_CHAR_AS_STRING, &array_iter); valid = oobs_list_get_iter_first (priv->services_list, &list_iter); while (correct && valid) { service = oobs_list_get (priv->services_list, &list_iter); correct = create_dbus_struct_from_service (OOBS_SERVICE (service), priv->runlevels, message, &array_iter); g_object_unref (service); valid = oobs_list_iter_next (priv->services_list, &list_iter); } dbus_message_iter_close_container (&iter, &array_iter); if (!correct) { /* malformed data, unset the message */ _oobs_object_set_dbus_message (object, NULL); } } /** * oobs_services_config_get: * @session: An #OobsSession. * * Returns the #OobsServicesConfig singleton, which represents * the services that are run during system init. * * Return Value: the singleton #OobsServicesConfig object. **/ OobsObject* oobs_services_config_get (OobsSession *session) { static OobsObject *object = NULL; g_return_val_if_fail (session != NULL, NULL); g_return_val_if_fail (OOBS_IS_SESSION (session), NULL); if (!object) { object = g_object_new (OOBS_TYPE_SERVICES_CONFIG, "remote-object", SERVICES_CONFIG_REMOTE_OBJECT, "session", session, NULL); oobs_object_update (object); } return object; } /** * oobs_services_config_get_services: * @config: An #OobsServicesConfig. * * Returns an #OobsList containing objects of type #OobsService. * The returned #OobsList is locked, meaning that new elements * can't be added nor removed. * * Return Value: an #OobsList containing the services list. **/ OobsList* oobs_services_config_get_services (OobsServicesConfig *config) { OobsServicesConfigPrivate *priv; g_return_val_if_fail (config != NULL, NULL); g_return_val_if_fail (OOBS_IS_SERVICES_CONFIG (config), NULL); priv = config->_priv; return priv->services_list; } /** * oobs_services_config_get_runlevels: * @config: An #OobsServicesConfig. * * Returns a list of #OobsServicesRunlevel describing the available * runlevels. * * Return Value: list of runlevels. the list must be freed with * g_list_free (); **/ GList* oobs_services_config_get_runlevels (OobsServicesConfig *config) { OobsServicesConfigPrivate *priv; g_return_val_if_fail (OOBS_IS_SERVICES_CONFIG (config), NULL); priv = config->_priv; return g_list_copy (priv->runlevels); } /** * oobs_services_config_get_default_runlevel: * @config: An #OobsServicesConfig. * * Returns the current runlevel. * * Return Value: An #OobsServicesRunlevel describing the current * runlevel. This value must not be freed, modified, * or stored. **/ G_CONST_RETURN OobsServicesRunlevel* oobs_services_config_get_default_runlevel (OobsServicesConfig *config) { OobsServicesConfigPrivate *priv; g_return_val_if_fail (OOBS_IS_SERVICES_CONFIG (config), NULL); priv = config->_priv; return priv->default_runlevel; }