Blame libteamdctl/cli_dbus.c

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 */