summaryrefslogtreecommitdiff
path: root/plugins/dbus_announce.c
blob: a82b2390872b78d65025dc547cd66c7e9b023ebf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "system.h"

#include <dbus/dbus.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>
#include "lib/rpmplugin.h"

struct dbus_announce_data {
    DBusConnection * bus;
};

static rpmRC dbus_announce_init(rpmPlugin plugin, rpmts ts)
{
    struct dbus_announce_data * state = rcalloc(1, sizeof(*state));
    rpmPluginSetData(plugin, state);
    return RPMRC_OK;
}

static void dbus_announce_close_bus(struct dbus_announce_data * state)
{
    if (state->bus) {
	dbus_connection_close(state->bus);
	dbus_connection_unref(state->bus);
	state->bus = NULL;
    }
}

static rpmRC open_dbus(rpmPlugin plugin, rpmts ts)
{
    DBusError err;
    int rc = 0;
    struct dbus_announce_data * state = rpmPluginGetData(plugin);

    /* Already open */
    if (state->bus)
	return RPMRC_OK;

    /* ...don't notify on test transactions */
    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
	return RPMRC_OK;

    /* ...don't notify on chroot transactions */
    if (!rstreq(rpmtsRootDir(ts), "/"))
	return RPMRC_OK;

    dbus_error_init(&err);

    state->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
    if (dbus_error_is_set(&err))
	goto err;

    if (state->bus)
	rc = dbus_bus_request_name(state->bus, "org.rpm.announce",
				   DBUS_NAME_FLAG_REPLACE_EXISTING , &err);

    if (dbus_error_is_set(&err))
	goto err;

    if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != rc) {
	dbus_announce_close_bus(state);
	goto err;
    }
    return RPMRC_OK;
 err:
    rpmlog(RPMLOG_WARNING,
	   "dbus_announce plugin: Error connecting to dbus (%s)\n",
	   err.message);
    dbus_error_free(&err);
    return RPMRC_OK;
}

static void dbus_announce_cleanup(rpmPlugin plugin)
{
    struct dbus_announce_data * state = rpmPluginGetData(plugin);
    dbus_announce_close_bus(state);
    free(state);
}

static rpmRC send_ts_message(rpmPlugin plugin,
			     const char * name,
			     rpmts ts,
			     int res)
{
    struct dbus_announce_data * state = rpmPluginGetData(plugin);
    DBusMessage* msg;
    char * dbcookie = NULL;

    if (!state->bus)
	return RPMRC_OK;

    msg = dbus_message_new_signal("/org/rpm/Transaction", /* object name */
				  "org.rpm.Transaction",  /* interface name */
				  name);                  /* signal name */
    if (msg == NULL)
	goto err;

    dbcookie = rpmdbCookie(rpmtsGetRdb(ts));
    rpm_tid_t tid = rpmtsGetTid(ts);
    if (!dbus_message_append_args(msg,
				  DBUS_TYPE_STRING, &dbcookie,
				  DBUS_TYPE_UINT32, &tid,
				  DBUS_TYPE_INVALID))
	goto err;

    if (!dbus_connection_send(state->bus, msg, NULL))
	goto err;

    dbus_connection_flush(state->bus);
    dbcookie = _free(dbcookie);

    return RPMRC_OK;

 err:
    rpmlog(RPMLOG_WARNING,
	   "dbus_announce plugin: Error sending message (%s)\n",
	   name);
    dbcookie = _free(dbcookie);
    return RPMRC_OK;
}

static rpmRC dbus_announce_tsm_pre(rpmPlugin plugin, rpmts ts)
{
    int rc;

    rc = open_dbus(plugin, ts);
    if (rc != RPMRC_OK)
	return rc;
    return send_ts_message(plugin, "StartTransaction", ts, RPMRC_OK);
}

static rpmRC dbus_announce_tsm_post(rpmPlugin plugin, rpmts ts, int res)
{
    return send_ts_message(plugin, "EndTransaction", ts, res);
}

struct rpmPluginHooks_s dbus_announce_hooks = {
    .init = dbus_announce_init,
    .cleanup = dbus_announce_cleanup,
    .tsm_pre = dbus_announce_tsm_pre,
    .tsm_post = dbus_announce_tsm_post,
};