udscs: add functions to associate per connection data with a connection
[vd_agent.git] / console-kit.c
blobcc71a0d7116f0f2fbf7dae9d92c662c8a1b2b83f
1 /* console-kit.h vdagentd ConsoleKit integration code
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "console-kit.h"
23 #include <dbus/dbus.h>
24 #include <stdbool.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
29 struct console_kit {
30 DBusConnection *connection;
31 char *seat;
32 char *active_session;
33 FILE *errfile;
36 static char *console_kit_get_first_seat(struct console_kit *ck);
37 static char *console_kit_check_active_session_change(struct console_kit *ck);
39 struct console_kit *console_kit_create(FILE *errfile)
41 struct console_kit *ck;
42 DBusError error;
43 char match[1024];
45 ck = calloc(1, sizeof(*ck));
46 if (!ck)
47 return NULL;
49 ck->errfile = errfile;
51 dbus_error_init(&error);
52 ck->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
53 if (ck->connection == NULL || dbus_error_is_set(&error)) {
54 if (dbus_error_is_set(&error)) {
55 fprintf(ck->errfile, "Unable to connect to system bus: %s\n",
56 error.message);
57 dbus_error_free(&error);
58 } else
59 fprintf(ck->errfile, "Unable to connect to system bus\n");
60 free(ck);
61 return NULL;
64 if (!console_kit_get_first_seat(ck)) {
65 console_kit_destroy(ck);
66 return NULL;
69 /* Register for active session changes */
70 snprintf(match, sizeof(match),
71 "type='signal',interface='org.freedesktop.ConsoleKit.Seat',"
72 "path='%s',member='ActiveSessionChanged'", ck->seat);
73 dbus_error_init(&error);
74 dbus_bus_add_match(ck->connection, match, &error);
75 if (dbus_error_is_set(&error)) {
76 fprintf(ck->errfile, "Match Error (%s)\n", error.message);
77 console_kit_destroy(ck);
78 return NULL;
81 if (!console_kit_get_active_session(ck)) {
82 console_kit_destroy(ck);
83 return NULL;
86 return ck;
89 void console_kit_destroy(struct console_kit *ck)
91 if (!ck)
92 return;
94 dbus_connection_close(ck->connection);
95 free(ck->seat);
96 free(ck->active_session);
97 free(ck);
100 static char *console_kit_get_first_seat(struct console_kit *ck)
102 DBusError error;
103 DBusMessage *message = NULL;
104 DBusMessage *reply = NULL;
105 DBusMessageIter iter, subiter;
106 int type;
107 char *seat = NULL;
109 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
110 "/org/freedesktop/ConsoleKit/Manager",
111 "org.freedesktop.ConsoleKit.Manager",
112 "GetSeats");
113 if (message == NULL) {
114 fprintf(ck->errfile, "Unable to create dbus message\n");
115 goto exit;
118 dbus_error_init(&error);
119 reply = dbus_connection_send_with_reply_and_block(ck->connection,
120 message,
122 &error);
123 if (reply == NULL || dbus_error_is_set(&error)) {
124 if (dbus_error_is_set(&error)) {
125 fprintf(ck->errfile, "GetSeats failed: %s\n",
126 error.message);
127 dbus_error_free(&error);
128 } else
129 fprintf(ck->errfile, "GetSeats failed\n");
130 goto exit;
133 dbus_message_iter_init(reply, &iter);
134 type = dbus_message_iter_get_arg_type(&iter);
135 if (type != DBUS_TYPE_ARRAY) {
136 fprintf(ck->errfile,
137 "expected an array return value, got a '%c' instead\n", type);
138 goto exit;
141 dbus_message_iter_recurse(&iter, &subiter);
142 type = dbus_message_iter_get_arg_type(&subiter);
143 if (type != DBUS_TYPE_OBJECT_PATH) {
144 fprintf(ck->errfile,
145 "expected an object path element, got a '%c' instead\n", type);
146 goto exit;
149 dbus_message_iter_get_basic(&subiter, &seat);
150 ck->seat = strdup(seat);
152 exit:
153 if (reply != NULL) {
154 dbus_message_unref(reply);
157 if (message != NULL) {
158 dbus_message_unref(message);
161 return ck->seat;
164 const char *console_kit_get_active_session(struct console_kit *ck)
166 DBusError error;
167 DBusMessage *message = NULL;
168 DBusMessage *reply = NULL;
169 char *session = NULL;
171 if (!ck)
172 return NULL;
174 if (ck->active_session)
175 return console_kit_check_active_session_change(ck);
177 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
178 ck->seat,
179 "org.freedesktop.ConsoleKit.Seat",
180 "GetActiveSession");
181 if (message == NULL) {
182 fprintf(ck->errfile, "Unable to create dbus message\n");
183 goto exit;
186 dbus_error_init(&error);
187 reply = dbus_connection_send_with_reply_and_block(ck->connection,
188 message,
190 &error);
191 if (reply == NULL || dbus_error_is_set(&error)) {
192 if (dbus_error_is_set(&error)) {
193 fprintf(ck->errfile, "GetSeats failed: %s\n",
194 error.message);
195 dbus_error_free(&error);
196 } else
197 fprintf(ck->errfile, "GetSeats failed\n");
198 goto exit;
201 dbus_error_init(&error);
202 if (!dbus_message_get_args(reply,
203 &error,
204 DBUS_TYPE_OBJECT_PATH, &session,
205 DBUS_TYPE_INVALID)) {
206 if (dbus_error_is_set(&error)) {
207 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
208 error.message);
209 dbus_error_free(&error);
210 } else
211 fprintf(ck->errfile, "error getting ssid from reply\n");
212 session = NULL;
213 goto exit;
216 ck->active_session = strdup(session);
218 exit:
219 if (reply != NULL) {
220 dbus_message_unref(reply);
223 if (message != NULL) {
224 dbus_message_unref(message);
227 return ck->active_session;
230 const char *console_kit_session_for_pid(struct console_kit *ck, uint32_t pid)
232 DBusError error;
233 DBusMessage *message = NULL;
234 DBusMessage *reply = NULL;
235 DBusMessageIter args;
236 char *ssid = NULL;
238 if (!ck)
239 return NULL;
241 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
242 "/org/freedesktop/ConsoleKit/Manager",
243 "org.freedesktop.ConsoleKit.Manager",
244 "GetSessionForUnixProcess");
245 if (message == NULL) {
246 fprintf(ck->errfile, "Unable to create dbus message\n");
247 goto exit;
250 dbus_message_iter_init_append(message, &args);
251 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
252 fprintf(ck->errfile, "Unable to append dbus message args\n");
253 goto exit;
256 dbus_error_init(&error);
257 reply = dbus_connection_send_with_reply_and_block(ck->connection,
258 message,
260 &error);
261 if (reply == NULL || dbus_error_is_set(&error)) {
262 if (dbus_error_is_set(&error)) {
263 fprintf(ck->errfile, "GetSessionForUnixProcess failed: %s\n",
264 error.message);
265 dbus_error_free(&error);
266 } else
267 fprintf(ck->errfile, "GetSessionForUnixProces failed\n");
268 goto exit;
271 dbus_error_init(&error);
272 if (!dbus_message_get_args(reply,
273 &error,
274 DBUS_TYPE_OBJECT_PATH, &ssid,
275 DBUS_TYPE_INVALID)) {
276 if (dbus_error_is_set(&error)) {
277 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
278 error.message);
279 dbus_error_free(&error);
280 } else
281 fprintf(ck->errfile, "error getting ssid from reply\n");
282 ssid = NULL;
283 goto exit;
286 ssid = strdup(ssid);
288 exit:
289 if (reply != NULL) {
290 dbus_message_unref(reply);
293 if (message != NULL) {
294 dbus_message_unref(message);
297 return ssid;
300 static char *console_kit_check_active_session_change(struct console_kit *ck)
302 DBusMessage *message = NULL;
303 DBusMessageIter iter;
304 char *session;
305 int type;
307 /* non blocking read of the next available message */
308 dbus_connection_read_write(ck->connection, 0);
309 while ((message = dbus_connection_pop_message(ck->connection))) {
310 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
311 const char *member = dbus_message_get_member (message);
312 if (!strcmp(member, "NameAcquired")) {
313 dbus_message_unref(message);
314 continue;
316 if (strcmp(member, "ActiveSessionChanged")) {
317 fprintf(ck->errfile, "unexpected signal member: %s\n", member);
318 dbus_message_unref(message);
319 continue;
321 } else {
322 fprintf(ck->errfile, "received non signal message!\n");
323 dbus_message_unref(message);
324 continue;
327 free(ck->active_session);
328 ck->active_session = NULL;
330 dbus_message_iter_init(message, &iter);
331 type = dbus_message_iter_get_arg_type(&iter);
332 /* Session should be an object path, but there is a bug in
333 ConsoleKit where it sends a string rather then an object_path
334 accept object_path too in case the bug ever gets fixed */
335 if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_OBJECT_PATH) {
336 fprintf(ck->errfile,
337 "ActiveSessionChanged message has unexpected type: '%c'\n",
338 type);
339 dbus_message_unref(message);
340 continue;
343 dbus_message_iter_get_basic(&iter, &session);
344 ck->active_session = strdup(session);
345 dbus_message_unref(message);
347 /* non blocking read of the next available message */
348 dbus_connection_read_write(ck->connection, 0);
351 return ck->active_session;