blob: afae68799b35d89937bb2ad0af6b554666192a2f [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <stdlib.h>
David Sodman8ef20062015-01-06 09:23:40 -08008
Stéphane Marchesin62561a12015-12-11 17:32:37 -08009#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -080010#include "dbus_interface.h"
11#include "image.h"
12#include "input.h"
13#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070014#include "util.h"
15
David Sodman8ef20062015-01-06 09:23:40 -080016#define COMMAND_MAKE_VT "MakeVT"
17#define COMMAND_SWITCH_VT "SwitchVT"
18#define COMMAND_TERMINATE "Terminate"
19#define COMMAND_IMAGE "Image"
20
21#define DBUS_DEFAULT_DELAY 3000
22
David Sodmanbbcb0522014-09-19 10:34:07 -070023struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080024 DBusConnection* conn;
David Sodmanbbcb0522014-09-19 10:34:07 -070025 int terminate;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080027 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070028 struct {
29 DBusObjectPathVTable vtable;
30 const char* interface;
31 const char* signal;
32 const char* rule;
33 void* user_data;
34 dbus_message_handler_t signal_handler;
35 } signal;
36};
37
David Sodman8ef20062015-01-06 09:23:40 -080038static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080039handle_switchvt(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -080040{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080041 DBusMessage* reply;
42 DBusMessage* msg;
David Sodman8ef20062015-01-06 09:23:40 -080043 DBusError error;
44 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080045 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -080046 unsigned int vt;
47
48 dbus_error_init(&error);
49 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
50 &vt, DBUS_TYPE_INVALID);
51
52 if (!stat) {
53 LOG(ERROR, "SwitchVT method error, no VT argument");
54 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
55 }
56
57 if (vt > input_get_maxterminals()) {
58 LOG(ERROR, "SwtichVT: invalid terminal");
59 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
60 }
61
62 if (vt == 0) {
63 terminal = input_create_term(vt);
64 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -070065 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080066 msg = dbus_message_new_method_call(
67 kLibCrosServiceName,
68 kLibCrosServicePath,
69 kLibCrosServiceInterface,
70 kTakeDisplayOwnership);
71 dbus_connection_send_with_reply_and_block(connection, msg,
72 DBUS_DEFAULT_DELAY, NULL);
73 }
74 reply = dbus_message_new_method_return(message);
75 dbus_connection_send(connection, reply, NULL);
76 return DBUS_HANDLER_RESULT_HANDLED;
77 } else {
78 /*
79 * If we are switching to a new term, and if a
80 * given term is active, then de-activate the
81 * current terminal
82 */
83 terminal = input_create_term(0);
84 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -070085 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080086
87 terminal = input_create_term(vt);
88 if (term_is_valid(terminal)) {
89 msg = dbus_message_new_method_call(
90 kLibCrosServiceName,
91 kLibCrosServicePath,
92 kLibCrosServiceInterface,
93 kReleaseDisplayOwnership);
94 dbus_connection_send_with_reply_and_block(connection, msg,
95 DBUS_DEFAULT_DELAY, NULL);
96 term_activate(terminal);
97
98 reply = dbus_message_new_method_return(message);
99 dbus_connection_send(connection, reply, NULL);
100 return DBUS_HANDLER_RESULT_HANDLED;
101 }
102 }
103
104 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
105}
106
107static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800108handle_makevt(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800109{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800110 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800111 DBusError error;
112 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800113 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -0800114 unsigned int vt;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800115 const char* reply_str;
David Sodman8ef20062015-01-06 09:23:40 -0800116
117 dbus_error_init(&error);
118 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
119 &vt, DBUS_TYPE_INVALID);
120
121 if (!stat) {
122 LOG(ERROR, "SwitchVT method error, not VT argument");
123 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
124 }
125
126 if ((vt < 1) || (vt > input_get_maxterminals())) {
127 LOG(ERROR, "SwtichVT: invalid terminal");
128 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
129 }
130
131 terminal = input_create_term(vt);
132 reply_str = term_get_ptsname(terminal);
133
134 reply = dbus_message_new_method_return(message);
135 dbus_message_append_args(reply,
136 DBUS_TYPE_STRING, &reply_str,
137 DBUS_TYPE_INVALID);
138 dbus_connection_send(connection, reply, NULL);
139
140 return DBUS_HANDLER_RESULT_HANDLED;
141}
142
143static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800144handle_terminate(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800145{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800146 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800147
148 reply = dbus_message_new_method_return(message);
149 dbus_connection_send(connection, reply, NULL);
150 exit(EXIT_SUCCESS);
151}
152
153
154#define NUM_IMAGE_PARAMETERS (2)
155static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800156handle_image(DBusConnection* connection, DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800157{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800158 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800159 DBusError error;
160 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800161 terminal_t* terminal;
162 image_t* image;
David Sodman8ef20062015-01-06 09:23:40 -0800163 int i;
164 int x, y;
165 char* option[NUM_IMAGE_PARAMETERS];
166 char* optname;
167 char* optval;
168 int status;
169
170 dbus_error_init(&error);
171 stat = dbus_message_get_args(message, &error,
172 DBUS_TYPE_STRING, &option[0],
173 DBUS_TYPE_STRING, &option[1],
174 DBUS_TYPE_INVALID);
175
176 image = image_create();
177 if (image == NULL) {
178 LOG(WARNING, "failed to create image");
179 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180 }
181
182 if (stat) {
183 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
184 optname = NULL;
185 optval = NULL;
186 parse_image_option(option[i], &optname, &optval);
187 if (strncmp(optname, "image", strlen("image")) == 0) {
188 image_set_filename(image, optval);
189 } else if (strncmp(optname, "location", strlen("location")) == 0) {
190 parse_location(optval, &x, &y);
191 image_set_location(image, x, y);
192 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
193 parse_location(optval, &x, &y);
194 image_set_offset(image, x, y);
195 }
196 if (optname)
197 free(optname);
198 if (optval)
199 free(optval);
200 }
201 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700202 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800203 }
204
205 status = image_load_image_from_file(image);
206 if (status != 0) {
207 LOG(WARNING, "image_load_image_from_file failed: %d", status);
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800209 }
210
211 terminal = input_create_term(0);
212 if (!terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700213 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800214
David Sodmanf0a925a2015-05-04 11:19:19 -0700215 status = term_show_image(terminal, image);
216 if (status != 0) {
217 LOG(WARNING, "term_show_image failed: %d", status);
218 goto fail;
219 }
David Sodman8ef20062015-01-06 09:23:40 -0800220 image_release(image);
221
222 reply = dbus_message_new_method_return(message);
223 dbus_connection_send(connection, reply, NULL);
224
225 return DBUS_HANDLER_RESULT_HANDLED;
David Sodmanf0a925a2015-05-04 11:19:19 -0700226fail:
227 if (image)
228 image_release(image);
229 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800230}
231
232static void
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800233frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800234{
235}
236
David Sodman8ef20062015-01-06 09:23:40 -0800237static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800238frecon_dbus_message_handler(DBusConnection* connection, DBusMessage* message, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800239{
240 if (dbus_message_is_method_call(message,
241 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800242 return handle_switchvt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800243 } else if (dbus_message_is_method_call(message,
244 kFreconDbusInterface, COMMAND_MAKE_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800245 return handle_makevt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800246 }
247 else if (dbus_message_is_method_call(message,
248 kFreconDbusInterface, COMMAND_TERMINATE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800249 return handle_terminate(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800250 } else if (dbus_message_is_method_call(message,
251 kFreconDbusInterface, COMMAND_IMAGE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800252 return handle_image(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800253 }
254
255 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
256
257}
258
259static DBusObjectPathVTable
260frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800261 frecon_dbus_unregister,
262 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -0800263 NULL
264};
265
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800266static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800267{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800268 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -0800269 dbus->watch = w;
270
271 return TRUE;
272}
273
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800274static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800275{
276}
277
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800278static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800279{
280}
281
David Sodmanbbcb0522014-09-19 10:34:07 -0700282dbus_t* dbus_init()
283{
284 dbus_t* new_dbus;
285 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800286 int result;
287 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700288
289 dbus_error_init(&err);
290
291 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
David Sodman8ef20062015-01-06 09:23:40 -0800292 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700293
294 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
295 if (dbus_error_is_set(&err)) {
296 LOG(ERROR, "Cannot get dbus connection");
297 free(new_dbus);
298 return NULL;
299 }
300
David Sodman8ef20062015-01-06 09:23:40 -0800301 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
302 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
303
304 if (result <= 0) {
305 LOG(ERROR, "Unable to get name for server");
306 }
307
308 stat = dbus_connection_register_object_path(new_dbus->conn,
309 kFreconDbusPath,
310 &frecon_vtable,
311 NULL);
312
313 if (!stat) {
314 LOG(ERROR, "failed to register object path");
315 }
316
317 stat = dbus_connection_set_watch_functions(new_dbus->conn,
318 add_watch, remove_watch, toggle_watch,
319 new_dbus, NULL);
320
321 if (!stat) {
322 LOG(ERROR, "Failed to set watch functions");
323 }
324
David Sodmanbbcb0522014-09-19 10:34:07 -0700325 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
326
327 return new_dbus;
328}
329
David Sodman003faed2014-11-03 09:02:10 -0800330bool dbus_method_call0(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800331 const char* service_path, const char* service_interface,
332 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800333{
334 DBusMessage *msg = NULL;
335
336 msg = dbus_message_new_method_call(service_name,
337 service_path, service_interface, method);
338
339 if (!msg)
340 return false;
341
342 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800343 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800344 dbus_message_unref(msg);
345 return false;
346 }
347
348 dbus_connection_flush(dbus->conn);
349 dbus_message_unref(msg);
350
351 return true;
352}
353
354bool dbus_method_call1(dbus_t* dbus, const char* service_name,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800355 const char* service_path, const char* service_interface,
356 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700357{
358 DBusMessage *msg = NULL;
359
360 msg = dbus_message_new_method_call(service_name,
361 service_path, service_interface, method);
362
363 if (!msg)
364 return false;
365
366 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700367 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700368 dbus_message_unref(msg);
369 return false;
370 }
371
372 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800373 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700374 dbus_message_unref(msg);
375 return false;
376 }
377
378 dbus_connection_flush(dbus->conn);
379 dbus_message_unref(msg);
380
381 return true;
382}
383
384static void
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800385dbus_path_unregister_function(DBusConnection* connection, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700386{
387}
388
389static DBusHandlerResult
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800390dbus_message_function(DBusConnection* connection,
391 DBusMessage* message, void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700392{
393 dbus_t* dbus = (dbus_t*)user_data;
394
395 if (dbus_message_is_signal(message, dbus->signal.interface,
396 dbus->signal.signal)) {
397 dbus->signal.signal_handler(dbus, dbus->signal.user_data);
398 }
399 return DBUS_HANDLER_RESULT_HANDLED;
400}
401
402bool dbus_signal_match_handler(
403 dbus_t* dbus,
404 const char* signal,
405 const char* path,
406 const char* interface,
407 const char* rule,
408 dbus_message_handler_t handler,
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800409 void* user_data)
David Sodmanbbcb0522014-09-19 10:34:07 -0700410{
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800411 DBusError err;
David Sodmanbbcb0522014-09-19 10:34:07 -0700412 dbus->signal.vtable.unregister_function = dbus_path_unregister_function;
413 dbus->signal.vtable.message_function = dbus_message_function;
414 dbus->signal.signal_handler = handler;
415 dbus->signal.signal = signal;
416 dbus->signal.user_data = user_data;
417 dbus->signal.interface = interface;
418
419 if (!dbus_connection_register_object_path(dbus->conn, path,
420 &dbus->signal.vtable, dbus)) {
421 LOG(ERROR, "register_object_path failed");
422 return false;
423 }
424
425 dbus_error_init(&err);
426 dbus_bus_add_match(dbus->conn, rule, &err);
427 if (dbus_error_is_set(&err)) {
428 LOG(ERROR, "add_match failed: %s", err.message);
429 return false;
430 }
431
432 return true;
433}
434
David Sodmanbbcb0522014-09-19 10:34:07 -0700435void dbus_destroy(dbus_t* dbus)
436{
437 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800438 * dbus_bus_get() is, unref documentation is rather
439 * unclear. Not a big issue but it would be nice to
440 * clean up properly here
441 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700442 /* dbus_connection_unref(dbus->conn); */
David Sodman8ef20062015-01-06 09:23:40 -0800443 if (dbus)
444 free(dbus);
445}
446
447void dbus_add_fd(dbus_t* dbus, fd_set* read_set, fd_set* exception_set)
448{
449 if (dbus->fd < 0)
450 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
451
452 if (dbus->fd >= 0) {
453 FD_SET(dbus->fd, read_set);
454 FD_SET(dbus->fd, exception_set);
455 }
456}
457
458int dbus_get_fd(dbus_t* dbus)
459{
460 if (dbus->fd < 0)
461 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
462
463 return dbus->fd;
464}
465
David Sodman8ef20062015-01-06 09:23:40 -0800466void dbus_dispatch_io(dbus_t* dbus)
467{
468 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
469 while (dbus_connection_get_dispatch_status(dbus->conn)
470 == DBUS_DISPATCH_DATA_REMAINS) {
471 dbus_connection_dispatch(dbus->conn);
472 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700473}