update .gitignore
[vd_agent.git] / console-kit.c
blob6a894885d95deefde0995f0d1d8495ca8d7ab77c
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 int fd;
32 char *seat;
33 char *active_session;
34 FILE *errfile;
37 static char *console_kit_get_first_seat(struct console_kit *ck);
38 static char *console_kit_check_active_session_change(struct console_kit *ck);
40 struct console_kit *console_kit_create(FILE *errfile)
42 struct console_kit *ck;
43 DBusError error;
44 char match[1024];
46 ck = calloc(1, sizeof(*ck));
47 if (!ck)
48 return NULL;
50 ck->errfile = errfile;
52 dbus_error_init(&error);
53 ck->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
54 if (ck->connection == NULL || dbus_error_is_set(&error)) {
55 if (dbus_error_is_set(&error)) {
56 fprintf(ck->errfile, "Unable to connect to system bus: %s\n",
57 error.message);
58 dbus_error_free(&error);
59 } else
60 fprintf(ck->errfile, "Unable to connect to system bus\n");
61 free(ck);
62 return NULL;
65 if (!dbus_connection_get_unix_fd(ck->connection, &ck->fd)) {
66 fprintf(ck->errfile, "Unable to get connection fd\n");
67 console_kit_destroy(ck);
68 return NULL;
71 if (!console_kit_get_first_seat(ck)) {
72 console_kit_destroy(ck);
73 return NULL;
76 /* Register for active session changes */
77 snprintf(match, sizeof(match),
78 "type='signal',interface='org.freedesktop.ConsoleKit.Seat',"
79 "path='%s',member='ActiveSessionChanged'", ck->seat);
80 dbus_error_init(&error);
81 dbus_bus_add_match(ck->connection, match, &error);
82 if (dbus_error_is_set(&error)) {
83 fprintf(ck->errfile, "Match Error (%s)\n", error.message);
84 console_kit_destroy(ck);
85 return NULL;
88 if (!console_kit_get_active_session(ck)) {
89 console_kit_destroy(ck);
90 return NULL;
93 return ck;
96 void console_kit_destroy(struct console_kit *ck)
98 if (!ck)
99 return;
101 dbus_connection_close(ck->connection);
102 free(ck->seat);
103 free(ck->active_session);
104 free(ck);
107 int console_kit_get_fd(struct console_kit *ck)
109 return ck->fd;
112 static char *console_kit_get_first_seat(struct console_kit *ck)
114 DBusError error;
115 DBusMessage *message = NULL;
116 DBusMessage *reply = NULL;
117 DBusMessageIter iter, subiter;
118 int type;
119 char *seat = NULL;
121 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
122 "/org/freedesktop/ConsoleKit/Manager",
123 "org.freedesktop.ConsoleKit.Manager",
124 "GetSeats");
125 if (message == NULL) {
126 fprintf(ck->errfile, "Unable to create dbus message\n");
127 goto exit;
130 dbus_error_init(&error);
131 reply = dbus_connection_send_with_reply_and_block(ck->connection,
132 message,
134 &error);
135 if (reply == NULL || dbus_error_is_set(&error)) {
136 if (dbus_error_is_set(&error)) {
137 fprintf(ck->errfile, "GetSeats failed: %s\n",
138 error.message);
139 dbus_error_free(&error);
140 } else
141 fprintf(ck->errfile, "GetSeats failed\n");
142 goto exit;
145 dbus_message_iter_init(reply, &iter);
146 type = dbus_message_iter_get_arg_type(&iter);
147 if (type != DBUS_TYPE_ARRAY) {
148 fprintf(ck->errfile,
149 "expected an array return value, got a '%c' instead\n", type);
150 goto exit;
153 dbus_message_iter_recurse(&iter, &subiter);
154 type = dbus_message_iter_get_arg_type(&subiter);
155 if (type != DBUS_TYPE_OBJECT_PATH) {
156 fprintf(ck->errfile,
157 "expected an object path element, got a '%c' instead\n", type);
158 goto exit;
161 dbus_message_iter_get_basic(&subiter, &seat);
162 ck->seat = strdup(seat);
164 exit:
165 if (reply != NULL) {
166 dbus_message_unref(reply);
169 if (message != NULL) {
170 dbus_message_unref(message);
173 return ck->seat;
176 const char *console_kit_get_active_session(struct console_kit *ck)
178 DBusError error;
179 DBusMessage *message = NULL;
180 DBusMessage *reply = NULL;
181 char *session = NULL;
183 if (!ck)
184 return NULL;
186 if (ck->active_session)
187 return console_kit_check_active_session_change(ck);
189 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
190 ck->seat,
191 "org.freedesktop.ConsoleKit.Seat",
192 "GetActiveSession");
193 if (message == NULL) {
194 fprintf(ck->errfile, "Unable to create dbus message\n");
195 goto exit;
198 dbus_error_init(&error);
199 reply = dbus_connection_send_with_reply_and_block(ck->connection,
200 message,
202 &error);
203 if (reply == NULL || dbus_error_is_set(&error)) {
204 if (dbus_error_is_set(&error)) {
205 fprintf(ck->errfile, "GetSeats failed: %s\n",
206 error.message);
207 dbus_error_free(&error);
208 } else
209 fprintf(ck->errfile, "GetSeats failed\n");
210 goto exit;
213 dbus_error_init(&error);
214 if (!dbus_message_get_args(reply,
215 &error,
216 DBUS_TYPE_OBJECT_PATH, &session,
217 DBUS_TYPE_INVALID)) {
218 if (dbus_error_is_set(&error)) {
219 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
220 error.message);
221 dbus_error_free(&error);
222 } else
223 fprintf(ck->errfile, "error getting ssid from reply\n");
224 session = NULL;
225 goto exit;
228 ck->active_session = strdup(session);
230 exit:
231 if (reply != NULL) {
232 dbus_message_unref(reply);
235 if (message != NULL) {
236 dbus_message_unref(message);
239 return ck->active_session;
242 char *console_kit_session_for_pid(struct console_kit *ck, uint32_t pid)
244 DBusError error;
245 DBusMessage *message = NULL;
246 DBusMessage *reply = NULL;
247 DBusMessageIter args;
248 char *ssid = NULL;
250 if (!ck)
251 return NULL;
253 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
254 "/org/freedesktop/ConsoleKit/Manager",
255 "org.freedesktop.ConsoleKit.Manager",
256 "GetSessionForUnixProcess");
257 if (message == NULL) {
258 fprintf(ck->errfile, "Unable to create dbus message\n");
259 goto exit;
262 dbus_message_iter_init_append(message, &args);
263 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
264 fprintf(ck->errfile, "Unable to append dbus message args\n");
265 goto exit;
268 dbus_error_init(&error);
269 reply = dbus_connection_send_with_reply_and_block(ck->connection,
270 message,
272 &error);
273 if (reply == NULL || dbus_error_is_set(&error)) {
274 if (dbus_error_is_set(&error)) {
275 fprintf(ck->errfile, "GetSessionForUnixProcess failed: %s\n",
276 error.message);
277 dbus_error_free(&error);
278 } else
279 fprintf(ck->errfile, "GetSessionForUnixProces failed\n");
280 goto exit;
283 dbus_error_init(&error);
284 if (!dbus_message_get_args(reply,
285 &error,
286 DBUS_TYPE_OBJECT_PATH, &ssid,
287 DBUS_TYPE_INVALID)) {
288 if (dbus_error_is_set(&error)) {
289 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
290 error.message);
291 dbus_error_free(&error);
292 } else
293 fprintf(ck->errfile, "error getting ssid from reply\n");
294 ssid = NULL;
295 goto exit;
298 ssid = strdup(ssid);
300 exit:
301 if (reply != NULL) {
302 dbus_message_unref(reply);
305 if (message != NULL) {
306 dbus_message_unref(message);
309 return ssid;
312 static char *console_kit_check_active_session_change(struct console_kit *ck)
314 DBusMessage *message = NULL;
315 DBusMessageIter iter;
316 char *session;
317 int type;
319 /* non blocking read of the next available message */
320 dbus_connection_read_write(ck->connection, 0);
321 while ((message = dbus_connection_pop_message(ck->connection))) {
322 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
323 const char *member = dbus_message_get_member (message);
324 if (!strcmp(member, "NameAcquired")) {
325 dbus_message_unref(message);
326 continue;
328 if (strcmp(member, "ActiveSessionChanged")) {
329 fprintf(ck->errfile, "unexpected signal member: %s\n", member);
330 dbus_message_unref(message);
331 continue;
333 } else {
334 fprintf(ck->errfile, "received non signal message!\n");
335 dbus_message_unref(message);
336 continue;
339 free(ck->active_session);
340 ck->active_session = NULL;
342 dbus_message_iter_init(message, &iter);
343 type = dbus_message_iter_get_arg_type(&iter);
344 /* Session should be an object path, but there is a bug in
345 ConsoleKit where it sends a string rather then an object_path
346 accept object_path too in case the bug ever gets fixed */
347 if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_OBJECT_PATH) {
348 fprintf(ck->errfile,
349 "ActiveSessionChanged message has unexpected type: '%c'\n",
350 type);
351 dbus_message_unref(message);
352 continue;
355 dbus_message_iter_get_basic(&iter, &session);
356 ck->active_session = strdup(session);
357 dbus_message_unref(message);
359 /* non blocking read of the next available message */
360 dbus_connection_read_write(ck->connection, 0);
363 return ck->active_session;