1
0
mirror of https://github.com/openSUSE/snapper.git synced 2026-02-05 15:46:00 +01:00
Files
snapper/examples/c/snapper_dbus_cli.c
2014-06-04 11:55:44 +02:00

1069 lines
23 KiB
C

/*
* Copyright (c) [2011-2012] Novell, Inc.
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* 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, contact Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail, you may
* find current contact information at www.novell.com.
*/
#include <dbus/dbus.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#define CDBUS_SIG_LIST_SNAPS_RSP "a(uquxussa{ss})"
#define CDBUS_SIG_LIST_CONFS_RSP "a(ssa{ss})"
#define CDBUS_SIG_CREATE_SNAP_RSP "u"
#define CDBUS_SIG_DEL_SNAPS_RSP ""
#define CDBUS_SIG_STRING_DICT "{ss}"
struct dict {
char *key;
char *val;
};
struct snap {
uint32_t id;
uint16_t type;
uint32_t pre_id;
int64_t time;
uint32_t creator_uid;
char *desc;
char *cleanup;
uint32_t num_user_data;
struct dict *user_data;
};
struct config {
char *name;
char *mnt;
uint32_t num_attrs;
struct dict *attrs;
};
static DBusConnection *cdbus_conn(void)
{
DBusError err;
DBusConnection *conn;
dbus_error_init(&err);
/* bus connection */
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "connection error: %s\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
return NULL;
}
return conn;
}
static int cdbus_msg_send(DBusConnection *conn,
DBusMessage *msg,
DBusPendingCall **pend_out)
{
DBusPendingCall *pending;
/* send message and get a handle for a reply */
if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
return -ENOMEM;
}
if (NULL == pending) {
fprintf(stderr, "Pending Call Null\n");
return -EINVAL;
}
dbus_connection_flush(conn);
*pend_out = pending;
return 0;
}
static int cdbus_msg_recv(DBusConnection *conn,
DBusPendingCall *pending,
DBusMessage **msg_out)
{
DBusMessage *msg;
/* block until we receive a reply */
dbus_pending_call_block(pending);
/* get the reply message */
msg = dbus_pending_call_steal_reply(pending);
if (msg == NULL) {
fprintf(stderr, "Reply Null\n");
return -ENOMEM;
}
/* free the pending message handle */
dbus_pending_call_unref(pending);
*msg_out = msg;
return 0;
}
static int cdbus_list_snaps_pack(char *snapper_conf,
DBusMessage **req_msg_out)
{
DBusMessage *msg;
DBusMessageIter args;
msg = dbus_message_new_method_call("org.opensuse.Snapper", /* target for the method call */
"/org/opensuse/Snapper", /* object to call on */
"org.opensuse.Snapper", /* interface to call on */
"ListSnapshots"); /* method name */
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
return -ENOMEM;
}
/* append arguments */
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
&snapper_conf)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
*req_msg_out = msg;
return 0;
}
static int cdbus_type_check(DBusMessageIter *iter, int expected_type)
{
int type = dbus_message_iter_get_arg_type(iter);
if (type != expected_type) {
fprintf(stderr, "got type %d, expecting %d\n",
type, expected_type);
return -EINVAL;
}
return 0;
}
static int cdbus_type_check_get(DBusMessageIter *iter, int expected_type,
void *val)
{
int ret;
ret = cdbus_type_check(iter, expected_type);
if (ret < 0) {
return ret;
}
dbus_message_iter_get_basic(iter, val);
return 0;
}
static int dict_unpack(DBusMessageIter *iter,
struct dict *dict_out)
{
int ret;
DBusMessageIter dct_iter;
if (cdbus_type_check(iter, DBUS_TYPE_DICT_ENTRY) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &dct_iter);
ret = cdbus_type_check_get(&dct_iter, DBUS_TYPE_STRING, &dict_out->key);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&dct_iter);
ret = cdbus_type_check_get(&dct_iter, DBUS_TYPE_STRING, &dict_out->val);
if (ret < 0) {
return ret;
}
return 0;
}
static void dict_array_print(uint32_t num_dicts,
struct dict *dicts)
{
uint32_t i;
for (i = 0; i < num_dicts; i++) {
printf("dict (\n"
"\tkey: %s\n"
"\tval: %s\n"
")\n",
dicts[i].key, dicts[i].val);
}
}
static int dict_array_unpack(DBusMessageIter *iter,
uint32_t *num_dicts_out,
struct dict **dicts_out)
{
int ret;
DBusMessageIter array_iter;
uint32_t num_dicts;
struct dict *dicts = NULL;
if (cdbus_type_check(iter, DBUS_TYPE_ARRAY) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &array_iter);
num_dicts = 0;
while (dbus_message_iter_get_arg_type(&array_iter)
!= DBUS_TYPE_INVALID) {
num_dicts++;
dicts = realloc(dicts, sizeof(struct dict) * num_dicts);
if (dicts == NULL)
abort();
ret = dict_unpack(&array_iter, &dicts[num_dicts - 1]);
if (ret < 0) {
free(dicts);
return ret;
}
dbus_message_iter_next(&array_iter);
}
*num_dicts_out = num_dicts;
*dicts_out = dicts;
return 0;
}
static int snap_struct_unpack(DBusMessageIter *iter,
struct snap *snap_out)
{
int ret;
DBusMessageIter st_iter;
if (cdbus_type_check(iter, DBUS_TYPE_STRUCT) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_UINT32,
&snap_out->id);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_UINT16,
&snap_out->type);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_UINT32,
&snap_out->pre_id);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_INT64,
&snap_out->time);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_UINT32,
&snap_out->creator_uid);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_STRING,
&snap_out->desc);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_STRING,
&snap_out->cleanup);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = dict_array_unpack(&st_iter, &snap_out->num_user_data,
&snap_out->user_data);
return ret;
}
static void snap_array_free(uint32_t num_snaps,
struct snap *snaps)
{
uint32_t i;
for (i = 0; i < num_snaps; i++) {
free(snaps[i].user_data);
}
free(snaps);
}
static void snap_array_print(uint32_t num_snaps,
struct snap *snaps)
{
uint32_t i;
for (i = 0; i < num_snaps; i++) {
printf("id: %u\n"
"type: %u\n"
"pre_id: %u\n"
"time: %" PRId64 "\n"
"creator_uid: %u\n"
"desc: %s\n"
"cleanup: %s\n",
snaps[i].id,
snaps[i].type,
snaps[i].pre_id,
snaps[i].time,
snaps[i].creator_uid,
snaps[i].desc,
snaps[i].cleanup);
dict_array_print(snaps[i].num_user_data, snaps[i].user_data);
printf("---\n");
}
}
static int snap_array_unpack(DBusMessageIter *iter,
uint32_t *num_snaps_out,
struct snap **snaps_out)
{
uint32_t num_snaps;
int ret;
struct snap *snaps = NULL;
DBusMessageIter array_iter;
if (cdbus_type_check(iter, DBUS_TYPE_ARRAY) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &array_iter);
num_snaps = 0;
while (dbus_message_iter_get_arg_type(&array_iter)
!= DBUS_TYPE_INVALID) {
num_snaps++;
snaps = realloc(snaps, sizeof(struct snap) * num_snaps);
if (snaps == NULL)
abort();
ret = snap_struct_unpack(&array_iter, &snaps[num_snaps - 1]);
if (ret < 0) {
free(snaps);
return ret;
}
dbus_message_iter_next(&array_iter);
}
*num_snaps_out = num_snaps;
*snaps_out = snaps;
return 0;
}
static int cdbus_list_snaps_unpack(DBusConnection *conn,
DBusMessage *rsp_msg,
uint32_t *num_snaps_out,
struct snap **snaps_out)
{
int ret;
DBusMessageIter iter;
int msg_type;
uint32_t num_snaps;
struct snap *snaps;
const char *sig;
msg_type = dbus_message_get_type(rsp_msg);
if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
fprintf(stderr, "list_snaps error response: %s\n",
dbus_message_get_error_name(rsp_msg));
return -EINVAL;
}
if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
fprintf(stderr, "unexpected list_snaps ret type: %d\n",
msg_type);
return -EINVAL;
}
sig = dbus_message_get_signature(rsp_msg);
if ((sig == NULL)
|| (strcmp(sig, CDBUS_SIG_LIST_SNAPS_RSP) != 0)) {
fprintf(stderr, "bad list snaps response sig: %s, "
"expected: %s\n",
(sig ? sig : "NULL"), CDBUS_SIG_LIST_SNAPS_RSP);
return -EINVAL;
}
/* read the parameters */
if (!dbus_message_iter_init(rsp_msg, &iter)) {
fprintf(stderr, "Message has no arguments!\n");
return -EINVAL;
}
ret = snap_array_unpack(&iter, &num_snaps, &snaps);
if (ret < 0) {
fprintf(stderr, "failed to unpack snap array\n");
return -EINVAL;
}
*num_snaps_out = num_snaps;
*snaps_out = snaps;
return 0;
}
static int cdbus_list_snaps_call(DBusConnection *conn)
{
int ret;
DBusMessage *req_msg;
DBusMessage *rsp_msg;
DBusPendingCall *pending;
uint32_t num_snaps = 0;
struct snap *snaps = NULL;
ret = cdbus_list_snaps_pack("root", &req_msg);
if (ret < 0) {
fprintf(stderr, "failed to pack list snaps request\n");
return ret;
}
ret = cdbus_msg_send(conn, req_msg, &pending);
if (ret < 0) {
dbus_message_unref(req_msg);
return ret;
}
ret = cdbus_msg_recv(conn, pending, &rsp_msg);
if (ret < 0) {
dbus_message_unref(req_msg);
dbus_pending_call_unref(pending);
return ret;
}
ret = cdbus_list_snaps_unpack(conn, rsp_msg,
&num_snaps, &snaps);
if (ret < 0) {
fprintf(stderr, "failed to unpack list snaps response\n");
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return ret;
}
snap_array_print(num_snaps, snaps);
snap_array_free(num_snaps, snaps);
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return 0;
}
static int cdbus_list_confs_pack(DBusMessage **req_msg_out)
{
DBusMessage *msg;
msg = dbus_message_new_method_call("org.opensuse.Snapper",
"/org/opensuse/Snapper",
"org.opensuse.Snapper",
"ListConfigs");
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
return -ENOMEM;
}
/* no arguments to append */
*req_msg_out = msg;
return 0;
}
static int conf_struct_unpack(DBusMessageIter *iter,
struct config *conf_out)
{
int ret;
DBusMessageIter st_iter;
if (cdbus_type_check(iter, DBUS_TYPE_STRUCT) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_STRING,
&conf_out->name);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = cdbus_type_check_get(&st_iter, DBUS_TYPE_STRING,
&conf_out->mnt);
if (ret < 0) {
return ret;
}
dbus_message_iter_next(&st_iter);
ret = dict_array_unpack(&st_iter, &conf_out->num_attrs,
&conf_out->attrs);
return ret;
}
static void conf_array_free(uint32_t num_confs,
struct config *confs)
{
uint32_t i;
for (i = 0; i < num_confs; i++) {
free(confs[i].attrs);
}
free(confs);
}
static void conf_array_print(uint32_t num_confs,
struct config *confs)
{
uint32_t i;
for (i = 0; i < num_confs; i++) {
printf("name: %s\n"
"mnt: %s\n",
confs[i].name, confs[i].mnt);
dict_array_print(confs[i].num_attrs, confs[i].attrs);
printf("---\n");
}
}
static int conf_array_unpack(DBusMessageIter *iter,
uint32_t *num_confs_out,
struct config **confs_out)
{
uint32_t num_confs;
int ret;
struct config *confs = NULL;
DBusMessageIter array_iter;
if (cdbus_type_check(iter, DBUS_TYPE_ARRAY) < 0) {
return -EINVAL;
}
dbus_message_iter_recurse(iter, &array_iter);
num_confs = 0;
while (dbus_message_iter_get_arg_type(&array_iter)
!= DBUS_TYPE_INVALID) {
num_confs++;
confs = realloc(confs, sizeof(struct config) * num_confs);
if (confs == NULL)
abort();
ret = conf_struct_unpack(&array_iter, &confs[num_confs - 1]);
if (ret < 0) {
free(confs);
return ret;
}
dbus_message_iter_next(&array_iter);
}
*num_confs_out = num_confs;
*confs_out = confs;
return 0;
}
static int cdbus_list_confs_unpack(DBusConnection *conn,
DBusMessage *rsp_msg,
uint32_t *num_confs_out,
struct config **confs_out)
{
int ret;
DBusMessageIter iter;
int msg_type;
uint32_t num_confs;
struct config *confs;
const char *sig;
msg_type = dbus_message_get_type(rsp_msg);
if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
fprintf(stderr, "list_confs error response: %s\n",
dbus_message_get_error_name(rsp_msg));
return -EINVAL;
}
if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
fprintf(stderr, "unexpected list_confs ret type: %d\n",
msg_type);
return -EINVAL;
}
sig = dbus_message_get_signature(rsp_msg);
if ((sig == NULL)
|| (strcmp(sig, CDBUS_SIG_LIST_CONFS_RSP) != 0)) {
fprintf(stderr, "bad list confs response sig: %s, "
"expected: %s\n",
(sig ? sig : "NULL"), CDBUS_SIG_LIST_CONFS_RSP);
return -EINVAL;
}
if (!dbus_message_iter_init(rsp_msg, &iter)) {
/* FIXME return empty? */
fprintf(stderr, "Message has no arguments!\n");
return -EINVAL;
}
ret = conf_array_unpack(&iter, &num_confs, &confs);
if (ret < 0) {
fprintf(stderr, "failed to unpack conf array\n");
return -EINVAL;
}
*num_confs_out = num_confs;
*confs_out = confs;
return 0;
}
static int cdbus_list_confs_call(DBusConnection *conn)
{
int ret;
DBusMessage *req_msg;
DBusMessage *rsp_msg;
DBusPendingCall *pending;
uint32_t num_confs = 0;
struct config *confs = NULL;
const char *sig;
ret = cdbus_list_confs_pack(&req_msg);
if (ret < 0) {
fprintf(stderr, "failed to pack list confs request\n");
return ret;
}
ret = cdbus_msg_send(conn, req_msg, &pending);
if (ret < 0) {
dbus_message_unref(req_msg);
return ret;
}
ret = cdbus_msg_recv(conn, pending, &rsp_msg);
if (ret < 0) {
dbus_message_unref(req_msg);
dbus_pending_call_unref(pending);
return ret;
}
sig = dbus_message_get_signature(rsp_msg);
if ((sig == NULL)
|| (strcmp(sig, CDBUS_SIG_LIST_CONFS_RSP) != 0)) {
fprintf(stderr, "bad list confs response sig: %s, "
"expected: %s\n",
(sig ? sig : "NULL"), CDBUS_SIG_LIST_CONFS_RSP);
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return -EINVAL;
}
ret = cdbus_list_confs_unpack(conn, rsp_msg,
&num_confs, &confs);
if (ret < 0) {
fprintf(stderr, "failed to unpack list confs response\n");
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return ret;
}
conf_array_print(num_confs, confs);
conf_array_free(num_confs, confs);
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return 0;
}
static int cdbus_create_snap_pack(char *snapper_conf,
char *desc,
uint32_t num_user_data,
struct dict *user_data,
DBusMessage **req_msg_out)
{
DBusMessage *msg;
DBusMessageIter args;
DBusMessageIter array_iter;
DBusMessageIter struct_iter;
const char *empty = "";
uint32_t i;
bool ret;
msg = dbus_message_new_method_call("org.opensuse.Snapper", /* target for the method call */
"/org/opensuse/Snapper", /* object to call on */
"org.opensuse.Snapper", /* interface to call on */
"CreateSingleSnapshot"); /* method name */
if (msg == NULL) {
fprintf(stderr, "failed to create req msg\n");
return -ENOMEM;
}
/* append arguments */
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
&snapper_conf)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
&desc)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
/* cleanup */
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
&empty)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
ret = dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
CDBUS_SIG_STRING_DICT,
&array_iter);
if (!ret) {
fprintf(stderr, "failed to open array container\n");
return -ENOMEM;
}
for (i = 0; i < num_user_data; i++) {
ret = dbus_message_iter_open_container(&array_iter,
DBUS_TYPE_DICT_ENTRY,
NULL, &struct_iter);
if (!ret) {
fprintf(stderr, "failed to open struct container\n");
return -ENOMEM;
}
if (!dbus_message_iter_append_basic(&struct_iter,
DBUS_TYPE_STRING,
&user_data[i].key)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
if (!dbus_message_iter_append_basic(&struct_iter,
DBUS_TYPE_STRING,
&user_data[i].val)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
ret = dbus_message_iter_close_container(&array_iter,
&struct_iter);
if (!ret) {
fprintf(stderr, "failed to close struct container\n");
return -ENOMEM;
}
}
dbus_message_iter_close_container(&args, &array_iter);
*req_msg_out = msg;
return 0;
}
static int cdbus_create_snap_unpack(DBusConnection *conn,
DBusMessage *rsp_msg,
uint32_t *snap_id_out)
{
DBusMessageIter iter;
int msg_type;
const char *sig;
msg_type = dbus_message_get_type(rsp_msg);
if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
fprintf(stderr, "create snap error response: %s\n",
dbus_message_get_error_name(rsp_msg));
return -EINVAL;
}
if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
fprintf(stderr, "unexpected create snap ret type: %d\n",
msg_type);
return -EINVAL;
}
sig = dbus_message_get_signature(rsp_msg);
if ((sig == NULL)
|| (strcmp(sig, CDBUS_SIG_CREATE_SNAP_RSP) != 0)) {
fprintf(stderr, "bad create snap response sig: %s, "
"expected: %s\n",
(sig ? sig : "NULL"), CDBUS_SIG_CREATE_SNAP_RSP);
return -EINVAL;
}
/* read the parameters */
if (!dbus_message_iter_init(rsp_msg, &iter)) {
fprintf(stderr, "Message has no arguments!\n");
return -EINVAL;
}
if (cdbus_type_check_get(&iter, DBUS_TYPE_UINT32, snap_id_out)) {
return -EINVAL;
}
return 0;
}
static int cdbus_create_snap_call(DBusConnection *conn)
{
int ret;
DBusMessage *req_msg;
DBusMessage *rsp_msg;
DBusPendingCall *pending;
uint32_t snap_id;
struct dict user_data[1];
user_data[0].key = "key data";
user_data[0].val = "val data";
ret = cdbus_create_snap_pack("root", "this is a desc", 1, user_data,
&req_msg);
if (ret < 0) {
fprintf(stderr, "failed to pack create snap request\n");
return ret;
}
ret = cdbus_msg_send(conn, req_msg, &pending);
if (ret < 0) {
dbus_message_unref(req_msg);
return ret;
}
ret = cdbus_msg_recv(conn, pending, &rsp_msg);
if (ret < 0) {
dbus_message_unref(req_msg);
dbus_pending_call_unref(pending);
return ret;
}
ret = cdbus_create_snap_unpack(conn, rsp_msg, &snap_id);
if (ret < 0) {
fprintf(stderr, "failed to unpack create snap response\n");
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return ret;
}
printf("created new snapshot %u\n", snap_id);
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return 0;
}
static int cdbus_del_snap_pack(char *snapper_conf,
uint32_t snap_id,
DBusMessage **req_msg_out)
{
DBusMessage *msg;
DBusMessageIter args;
DBusMessageIter array_iter;
bool ret;
msg = dbus_message_new_method_call("org.opensuse.Snapper",
"/org/opensuse/Snapper",
"org.opensuse.Snapper",
"DeleteSnapshots");
if (msg == NULL) {
fprintf(stderr, "failed to create req msg\n");
return -ENOMEM;
}
/* append arguments */
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
&snapper_conf)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
ret = dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
DBUS_TYPE_UINT32_AS_STRING,
&array_iter);
if (!ret) {
fprintf(stderr, "failed to open array container\n");
return -ENOMEM;
}
if (!dbus_message_iter_append_basic(&array_iter,
DBUS_TYPE_UINT32,
&snap_id)) {
fprintf(stderr, "Out Of Memory!\n");
return -ENOMEM;
}
dbus_message_iter_close_container(&args, &array_iter);
*req_msg_out = msg;
return 0;
}
static int cdbus_del_snap_unpack(DBusConnection *conn,
DBusMessage *rsp_msg)
{
int msg_type;
const char *sig;
msg_type = dbus_message_get_type(rsp_msg);
if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
fprintf(stderr, "del snap error response: %s\n",
dbus_message_get_error_name(rsp_msg));
return -EINVAL;
}
if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
fprintf(stderr, "unexpected del snap ret type: %d\n",
msg_type);
return -EINVAL;
}
sig = dbus_message_get_signature(rsp_msg);
if ((sig == NULL)
|| (strcmp(sig, CDBUS_SIG_DEL_SNAPS_RSP) != 0)) {
fprintf(stderr, "bad del snap response sig: %s, "
"expected: %s\n",
(sig ? sig : "NULL"), CDBUS_SIG_DEL_SNAPS_RSP);
return -EINVAL;
}
/* no parameters in response */
return 0;
}
static int cdbus_del_snap_call(DBusConnection *conn,
uint32_t snap_id)
{
int ret;
DBusMessage *req_msg;
DBusMessage *rsp_msg;
DBusPendingCall *pending;
ret = cdbus_del_snap_pack("root", snap_id, &req_msg);
if (ret < 0) {
fprintf(stderr, "failed to pack del snap request\n");
return ret;
}
ret = cdbus_msg_send(conn, req_msg, &pending);
if (ret < 0) {
dbus_message_unref(req_msg);
return ret;
}
ret = cdbus_msg_recv(conn, pending, &rsp_msg);
if (ret < 0) {
dbus_message_unref(req_msg);
dbus_pending_call_unref(pending);
return ret;
}
ret = cdbus_del_snap_unpack(conn, rsp_msg);
if (ret < 0) {
fprintf(stderr, "failed to unpack del snap response\n");
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return ret;
}
printf("deleted snapshot %u\n", snap_id);
dbus_message_unref(req_msg);
dbus_message_unref(rsp_msg);
return 0;
}
int main(int argc, char **argv)
{
DBusConnection *conn;
int ret = -EINVAL;
if (argc < 2) {
fprintf(stderr, "Syntax: %s <list_confs | list_snaps | create_snap | del_snap> <arg>\n",
argv[0]);
return -EINVAL;
}
conn = cdbus_conn();
if (conn == NULL) {
fprintf(stderr, "connect failed\n");
return -ENOMEM;
}
if (!strcmp(argv[1], "list_confs")) {
ret = cdbus_list_confs_call(conn);
} else if (!strcmp(argv[1], "list_snaps")) {
ret = cdbus_list_snaps_call(conn);
} else if (!strcmp(argv[1], "create_snap")) {
ret = cdbus_create_snap_call(conn);
} else if (!strcmp(argv[1], "del_snap")) {
if (argc < 3) {
fprintf(stderr, "del_snap requires a snapshot_id argument\n");
return -EINVAL;
}
ret = cdbus_del_snap_call(conn, atoi(argv[2]));
} else {
fprintf(stderr, "Syntax: %s <list_confs | list_snaps | create_snap> | del_snap> <arg>\n",
argv[0]);
ret = -EINVAL;
goto err_conn_close;
}
if (ret < 0) {
fprintf(stderr, "%s call failed: %s\n",
argv[1], strerror(-ret));
}
err_conn_close:
dbus_connection_unref(conn);
return ret;
}