blob: af4b509c5fa6a78f9b08966855eab266547a7dc6 [file] [log] [blame]
/*
* vim:noexpandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2013, Panasas Inc.
* Contributor : Jim Lieb <jlieb@panasas.com>
*
* Some portions Copyright CEA/DAM/DIF (2008)
* contributeur : Philippe DENIEL philippe.deniel@cea.fr
* Thomas LEIBOVICI thomas.leibovici@cea.fr
*
*
* 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 3 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
* 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
*
* -------------
*/
#include "config.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <time.h>
#include <pthread.h>
#include <assert.h>
#include "gsh_list.h"
#include "fsal.h"
#include "nfs_core.h"
#include "log.h"
#include "nfs_rpc_callback.h"
#include "gsh_dbus.h"
#include <os/memstream.h>
#include "dbus_priv.h"
#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
#define DBUS_ERROR_UNKNOWN_INTERFACE \
"org.freedesktop.DBus.Error.UnknownInterface"
#endif
#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
#define DBUS_ERROR_UNKNOWN_PROPERTY \
"org.freedesktop.DBus.Error.UnknownProperty"
#endif
#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
#define DBUS_ERROR_PROPERTY_READ_ONLY \
"org.freedesktop.DBus.Error.PropertyReadOnly"
#endif
/**
* @brief The properties interface for properties interfaces
*
* Seems if introspect says we have a properties interface for an
* object, scanners want to wall it to see if it has its own props.
* Fake one here because properties doesn't have properties; signals
* maybe but no props.
*/
static struct gsh_dbus_interface props_interface = {
.name = DBUS_INTERFACE_PROPERTIES,
.props = NULL,
.methods = NULL,
.signals = NULL
};
static struct gsh_dbus_interface *props_ptr = &props_interface;
static inline struct gsh_dbus_interface **lookup_interface(const char
*interface,
struct
gsh_dbus_interface
**interfaces,
DBusError *error)
{
struct gsh_dbus_interface **iface;
if (strcmp(interface, DBUS_INTERFACE_PROPERTIES) == 0)
return &props_ptr;
for (iface = interfaces; *iface; iface++) {
if (strcmp(interface, (*iface)->name) == 0)
break;
}
if (*iface == NULL) {
dbus_set_error(error, DBUS_ERROR_UNKNOWN_INTERFACE,
"Requested interface: %s", interface);
}
return iface;
}
static inline struct gsh_dbus_prop **lookup_property(const char *prop_name,
struct gsh_dbus_interface
**iface,
DBusError *error)
{
struct gsh_dbus_prop **prop;
for (prop = (*iface)->props; prop && *prop; prop++) {
if (strcmp(prop_name, (*prop)->name) == 0)
break;
}
if (prop == NULL) {
dbus_set_error(error, DBUS_ERROR_UNKNOWN_PROPERTY,
"Requested property: %s from %s", prop_name,
(*iface)->name);
}
return prop;
}
/**
*
* @brief Handle object properties
*
* Handle the three methods of the properties interface.
*
* @param argsp [IN] The message
* @param reply [IN/OUT] Our reply
*
* @return bool success or failure if bad request
*/
bool dbus_proc_property(const char *method, DBusMessage *msg,
DBusMessage *reply, DBusError *error,
struct gsh_dbus_interface **interfaces)
{
const char *interface;
const char *prop_name;
bool retval = false;
struct gsh_dbus_interface **iface;
struct gsh_dbus_prop **prop;
DBusMessageIter reply_iter;
dbus_message_iter_init_append(reply, &reply_iter);
if (strcmp(method, "GetAll") == 0) {
DBusMessageIter getall_dict, dict_entry, val_iter;
if (!dbus_message_get_args
(msg, error, DBUS_TYPE_STRING, &interface,
DBUS_TYPE_INVALID))
goto err_out;
iface = lookup_interface(interface, interfaces, error);
if (*iface == NULL)
goto err_out;
if (!dbus_message_iter_open_container
(&reply_iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &getall_dict))
goto getall_err;
for (prop = (*iface)->props; prop && *prop; prop++) {
prop_name = (*prop)->name;
if ((*prop)->access == DBUS_PROP_READ
|| (*prop)->access == DBUS_PROP_READWRITE) {
if (!dbus_message_iter_open_container
(&getall_dict, DBUS_TYPE_DICT_ENTRY, NULL,
&dict_entry))
goto getall_err;
if (!dbus_message_iter_append_basic
(&dict_entry, DBUS_TYPE_STRING, &prop_name))
goto getall_err;
if (!dbus_message_iter_open_container
(&dict_entry, DBUS_TYPE_VARIANT,
(*prop)->type, &val_iter))
goto getall_err;
if (!(*prop)->get(&val_iter))
goto getall_err;
if (!dbus_message_iter_close_container
(&dict_entry, &val_iter))
goto getall_err;
if (!dbus_message_iter_close_container
(&getall_dict, &dict_entry))
goto getall_err;
} else {
dbus_set_error(error,
DBUS_ERROR_PROPERTY_READ_ONLY,
"%s of %s from %s (write only?)",
method, prop_name, interface);
/** @todo@ check does write only make sense?? */
goto err_out;
}
}
if (!dbus_message_iter_close_container
(&reply_iter, &getall_dict))
goto getall_err;
return true; /* DONE! */
} else if (strcmp(method, "Get") == 0) {
if (!dbus_message_get_args
(msg, error, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING,
&prop_name, DBUS_TYPE_INVALID))
goto err_out;
iface = lookup_interface(interface, interfaces, error);
if (*iface == NULL)
goto err_out;
prop = lookup_property(prop_name, iface, error);
if (*prop == NULL)
goto err_out;
if ((*prop)->access == DBUS_PROP_READ
|| (*prop)->access == DBUS_PROP_READWRITE) {
DBusMessageIter variant_iter;
if (!dbus_message_iter_open_container
(&reply_iter, DBUS_TYPE_VARIANT, (*prop)->type,
&variant_iter)) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"Couldn't open Get container");
goto err_out;
}
retval = (*prop)->get(&variant_iter);
if (retval == false ||
!dbus_message_iter_close_container(&reply_iter,
&variant_iter)) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
"Couldn't close Get container");
goto err_out;
}
} else {
dbus_set_error(error, DBUS_ERROR_PROPERTY_READ_ONLY,
"%s of %s from %s (write only?)", method,
prop_name, interface);
/** @todo@ check does write only make sense?? */
goto err_out;
}
return true; /* DONE! */
} else if (strcmp(method, "Set") == 0) {
DBusMessageIter iter_args;
if (!dbus_message_iter_init(msg, &iter_args)
|| dbus_message_iter_get_arg_type(&iter_args) !=
DBUS_TYPE_STRING) {
goto invalid_args;
}
dbus_message_iter_get_basic(&iter_args, &interface);
if (!dbus_message_iter_next(&iter_args)
|| dbus_message_iter_get_arg_type(&iter_args) !=
DBUS_TYPE_STRING) {
goto invalid_args;
}
dbus_message_iter_get_basic(&iter_args, &prop_name);
if (!dbus_message_iter_next(&iter_args)
|| dbus_message_iter_get_arg_type(&iter_args) !=
DBUS_TYPE_VARIANT
|| dbus_message_iter_has_next(&iter_args)) {
goto invalid_args;
}
iface = lookup_interface(interface, interfaces, error);
if (*iface == NULL)
goto err_out;
prop = lookup_property(prop_name, iface, error);
if (*prop == NULL)
goto err_out;
if ((*prop)->access == DBUS_PROP_WRITE
|| (*prop)->access == DBUS_PROP_READWRITE) {
DBusMessageIter arg;
dbus_message_iter_recurse(&iter_args, &arg);
return (*prop)->set(&arg); /* DONE! */
} else {
dbus_set_error(error, DBUS_ERROR_PROPERTY_READ_ONLY,
"%s of %s from %s", method, prop_name,
interface);
goto err_out;
}
} else {
dbus_set_error(error, DBUS_ERROR_UNKNOWN_METHOD,
"Requested method: %s", method);
}
return retval;
getall_err:
dbus_set_error(error, DBUS_ERROR_FAILED, "GetAll container failure");
goto err_out;
invalid_args:
dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Method %s", method);
err_out:
return retval;
}