|
Packit |
cac203 |
/*
|
|
Packit |
cac203 |
* cli_dbus.c - Teamd daemon control library D-Bus client
|
|
Packit |
cac203 |
* Copyright (C) 2013-2015 Jiri Pirko <jiri@resnulli.us>
|
|
Packit |
cac203 |
*
|
|
Packit |
cac203 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
cac203 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
cac203 |
* License as published by the Free Software Foundation; either
|
|
Packit |
cac203 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
cac203 |
*
|
|
Packit |
cac203 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
cac203 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
cac203 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
cac203 |
* Lesser General Public License for more details.
|
|
Packit |
cac203 |
*
|
|
Packit |
cac203 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
cac203 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
cac203 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
cac203 |
*/
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
#include "config.h"
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
#ifdef ENABLE_DBUS
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
#include <stdio.h>
|
|
Packit |
cac203 |
#include <stdarg.h>
|
|
Packit |
cac203 |
#include <string.h>
|
|
Packit |
cac203 |
#include <stdlib.h>
|
|
Packit |
cac203 |
#include <errno.h>
|
|
Packit |
cac203 |
#include <dbus/dbus.h>
|
|
Packit |
cac203 |
#include <teamdctl.h>
|
|
Packit |
cac203 |
#include "teamdctl_private.h"
|
|
Packit |
cac203 |
#include "../teamd/teamd_dbus_common.h"
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
struct cli_dbus_priv {
|
|
Packit |
cac203 |
DBusConnection *conn;
|
|
Packit |
cac203 |
char *service_name;
|
|
Packit |
cac203 |
};
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
static int cli_dbus_check_error_msg(struct teamdctl *tdc, DBusMessage *msg)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
DBusMessageIter args;
|
|
Packit |
cac203 |
dbus_bool_t dbres;
|
|
Packit |
cac203 |
char *param = NULL;
|
|
Packit |
cac203 |
const char *err_msg;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
err_msg = dbus_message_get_error_name(msg);
|
|
Packit |
cac203 |
if (!err_msg)
|
|
Packit |
cac203 |
return 0;
|
|
Packit |
cac203 |
err(tdc, "dbus: Error message received: \"%s\"", err_msg);
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbres = dbus_message_iter_init(msg, &args);
|
|
Packit |
cac203 |
if (dbres == TRUE) {
|
|
Packit |
cac203 |
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Received argument is not string as expected.");
|
|
Packit |
cac203 |
return -EINVAL;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
dbus_message_iter_get_basic(&args, ¶m;;
|
|
Packit |
cac203 |
err(tdc, "dbus: Error message content: \"%s\"", param);
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
return -EINVAL;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
static int cli_dbus_get_reply_str(struct teamdctl *tdc, char **p_reply,
|
|
Packit |
cac203 |
DBusMessage *msg)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
DBusMessageIter args;
|
|
Packit |
cac203 |
dbus_bool_t dbres;
|
|
Packit |
cac203 |
char *param = NULL;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbres = dbus_message_iter_init(msg, &args);
|
|
Packit |
cac203 |
if (dbres == FALSE) {
|
|
Packit |
cac203 |
err(tdc, "Failed, no data received.");
|
|
Packit |
cac203 |
return -EINVAL;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Received argument is not string as expected.");
|
|
Packit |
cac203 |
return -EINVAL;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
dbus_message_iter_get_basic(&args, ¶m;;
|
|
Packit |
cac203 |
*p_reply = param;
|
|
Packit |
cac203 |
return 0;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
static int cli_dbus_method_call(struct teamdctl *tdc, const char *method_name,
|
|
Packit |
cac203 |
char **p_reply, void *priv,
|
|
Packit |
cac203 |
const char *fmt, va_list ap)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
struct cli_dbus_priv *cli_dbus = priv;
|
|
Packit |
cac203 |
char *str;
|
|
Packit |
cac203 |
DBusMessage *msg;
|
|
Packit |
cac203 |
DBusMessageIter iter;
|
|
Packit |
cac203 |
dbus_bool_t dbres;
|
|
Packit |
cac203 |
DBusPendingCall *pending;
|
|
Packit |
cac203 |
char *reply;
|
|
Packit |
cac203 |
int err;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbg(tdc, "dbus: Calling method \"%s\"", method_name);
|
|
Packit |
cac203 |
msg = dbus_message_new_method_call(cli_dbus->service_name,
|
|
Packit |
cac203 |
TEAMD_DBUS_PATH, TEAMD_DBUS_IFACE,
|
|
Packit |
cac203 |
method_name);
|
|
Packit |
cac203 |
if (!msg) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Failed to create message.");
|
|
Packit |
cac203 |
return -ENOMEM;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
dbus_message_iter_init_append(msg, &iter);
|
|
Packit |
cac203 |
while (*fmt) {
|
|
Packit |
cac203 |
switch (*fmt++) {
|
|
Packit |
cac203 |
case 's': /* string */
|
|
Packit |
cac203 |
str = va_arg(ap, char *);
|
|
Packit |
cac203 |
dbres = dbus_message_iter_append_basic(&iter,
|
|
Packit |
cac203 |
DBUS_TYPE_STRING,
|
|
Packit |
cac203 |
&str);
|
|
Packit |
cac203 |
if (dbres == FALSE) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Failed to construct message.");
|
|
Packit |
cac203 |
err = -ENOMEM;
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
break;
|
|
Packit |
cac203 |
default:
|
|
Packit |
cac203 |
err(tdc, "dbus: Unknown argument type requested.");
|
|
Packit |
cac203 |
err = -EINVAL;
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbres = dbus_connection_send_with_reply(cli_dbus->conn, msg,
|
|
Packit |
cac203 |
&pending, TEAMDCTL_REPLY_TIMEOUT);
|
|
Packit |
cac203 |
if (dbres == FALSE) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Send with reply failed.");
|
|
Packit |
cac203 |
err = -ENOMEM;
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
if (!pending) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Pending call not created.");
|
|
Packit |
cac203 |
err = -ENOMEM;
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbus_pending_call_block(pending);
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbus_message_unref(msg);
|
|
Packit |
cac203 |
msg = dbus_pending_call_steal_reply(pending);
|
|
Packit |
cac203 |
dbus_pending_call_unref(pending);
|
|
Packit |
cac203 |
if (!msg) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Failed to get reply.");
|
|
Packit |
cac203 |
err = -EINVAL;
|
|
Packit |
cac203 |
goto out;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
err = cli_dbus_check_error_msg(tdc, msg);
|
|
Packit |
cac203 |
if (err)
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
if (p_reply) {
|
|
Packit |
cac203 |
err = cli_dbus_get_reply_str(tdc, &reply, msg);
|
|
Packit |
cac203 |
if (err)
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
reply = strdup(reply);
|
|
Packit |
cac203 |
if (!reply) {
|
|
Packit |
cac203 |
err = -ENOMEM;
|
|
Packit |
cac203 |
goto free_msg;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
*p_reply = reply;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
free_msg:
|
|
Packit |
cac203 |
dbus_message_unref(msg);
|
|
Packit |
cac203 |
out:
|
|
Packit |
cac203 |
return err;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
static int cli_dbus_init(struct teamdctl *tdc, const char *team_name, void *priv)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
struct cli_dbus_priv *cli_dbus = priv;
|
|
Packit |
cac203 |
DBusError error;
|
|
Packit |
cac203 |
int ret;
|
|
Packit |
cac203 |
int err;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
ret = asprintf(&cli_dbus->service_name, TEAMD_DBUS_SERVICE ".%s",
|
|
Packit |
cac203 |
team_name);
|
|
Packit |
cac203 |
if (ret == -1)
|
|
Packit |
cac203 |
return -errno;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
dbus_error_init(&error);
|
|
Packit |
cac203 |
cli_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
|
Packit |
cac203 |
if (!cli_dbus->conn) {
|
|
Packit |
cac203 |
err(tdc, "dbus: Could not acquire the system bus: %s - %s",
|
|
Packit |
cac203 |
error.name, error.message);
|
|
Packit |
cac203 |
err = -EINVAL;
|
|
Packit |
cac203 |
goto free_service_name;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
err = 0;
|
|
Packit |
cac203 |
goto free_error;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
free_service_name:
|
|
Packit |
cac203 |
free(cli_dbus->service_name);
|
|
Packit |
cac203 |
free_error:
|
|
Packit |
cac203 |
dbus_error_free(&error);
|
|
Packit |
cac203 |
return err;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
void cli_dbus_fini(struct teamdctl *tdc, void *priv)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
struct cli_dbus_priv *cli_dbus = priv;
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
free(cli_dbus->service_name);
|
|
Packit |
cac203 |
dbus_connection_unref(cli_dbus->conn);
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
static const struct teamdctl_cli cli_dbus = {
|
|
Packit |
cac203 |
.name = "dbus",
|
|
Packit |
cac203 |
.init = cli_dbus_init,
|
|
Packit |
cac203 |
.fini = cli_dbus_fini,
|
|
Packit |
cac203 |
.test_method_call_required = true,
|
|
Packit |
cac203 |
.method_call = cli_dbus_method_call,
|
|
Packit |
cac203 |
.priv_size = sizeof(struct cli_dbus_priv),
|
|
Packit |
cac203 |
};
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
const struct teamdctl_cli *teamdctl_cli_dbus_get(void)
|
|
Packit |
cac203 |
{
|
|
Packit |
cac203 |
return &cli_dbus;
|
|
Packit |
cac203 |
}
|
|
Packit |
cac203 |
|
|
Packit |
cac203 |
#endif /* ENABLE_DBUS */
|