chiark / gitweb /
logind: implement D-Bus properties
[elogind.git] / src / logind-seat-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "logind.h"
25 #include "logind-seat.h"
26 #include "dbus-common.h"
27 #include "util.h"
28
29 #define BUS_SEAT_INTERFACE \
30         " <interface name=\"org.freedesktop.login1.Seat\">\n"           \
31         "  <method name=\"Terminate\"/>\n"                              \
32         "  <property name=\"Id\" type=\"s\" access=\"read\"/>\n"        \
33         "  <property name=\"Active\" type=\"so\" access=\"read\"/>\n"   \
34         "  <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
35         " </interface>\n"                                               \
36
37 #define INTROSPECTION                                                   \
38         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
39         "<node>\n"                                                      \
40         BUS_SEAT_INTERFACE                                              \
41         BUS_PROPERTIES_INTERFACE                                        \
42         BUS_PEER_INTERFACE                                              \
43         BUS_INTROSPECTABLE_INTERFACE                                    \
44         "</node>\n"
45
46 #define INTERFACES_LIST                              \
47         BUS_GENERIC_INTERFACES_LIST                  \
48         "org.freedesktop.login1.Seat\0"
49
50 static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
51         DBusMessageIter sub;
52         Seat *s = data;
53         const char *id, *path;
54         char *p = NULL;
55
56         assert(i);
57         assert(property);
58         assert(s);
59
60         if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
61                 return -ENOMEM;
62
63         if (s->active) {
64                 id = s->active->id;
65                 path = p = session_bus_path(s->active);
66
67                 if (!p)
68                         return -ENOMEM;
69         } else {
70                 id = "";
71                 path = "/";
72         }
73
74         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
75             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
76                 free(p);
77                 return -ENOMEM;
78         }
79
80         free(p);
81
82         if (!dbus_message_iter_close_container(i, &sub))
83                 return -ENOMEM;
84
85         return 0;
86 }
87
88 static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
89         DBusMessageIter sub, sub2;
90         Seat *s = data;
91         Session *session;
92
93         assert(i);
94         assert(property);
95         assert(s);
96
97         if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
98                 return -ENOMEM;
99
100         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
101                 char *p;
102
103                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
104                         return -ENOMEM;
105
106                 p = session_bus_path(session);
107                 if (!p)
108                         return -ENOMEM;
109
110                 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
111                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
112                         free(p);
113                         return -ENOMEM;
114                 }
115
116                 free(p);
117
118                 if (!dbus_message_iter_close_container(&sub, &sub2))
119                         return -ENOMEM;
120         }
121
122         if (!dbus_message_iter_close_container(i, &sub))
123                 return -ENOMEM;
124
125         return 0;
126 }
127
128 static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
129         Seat *s;
130         char *id;
131
132         assert(m);
133         assert(path);
134         assert(_s);
135
136         if (!startswith(path, "/org/freedesktop/login1/seat/"))
137                 return -EINVAL;
138
139         id = bus_path_unescape(path + 29);
140         if (!id)
141                 return -ENOMEM;
142
143         s = hashmap_get(m->seats, id);
144         free(id);
145
146         if (!s)
147                 return -ENOENT;
148
149         *_s = s;
150         return 0;
151 }
152
153 static DBusHandlerResult seat_message_dispatch(
154                 Seat *s,
155                 DBusConnection *connection,
156                 DBusMessage *message) {
157
158         const BusProperty properties[] = {
159                 { "org.freedesktop.login1.Seat", "Id",       bus_property_append_string, "s",     s->id },
160                 { "org.freedesktop.login1.Seat", "Active",   bus_seat_append_active,     "(so)",  s     },
161                 { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions,   "a(so)", s     },
162                 { NULL, NULL, NULL, NULL, NULL }
163         };
164
165         assert(s);
166         assert(connection);
167         assert(message);
168
169         return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
170 }
171
172 static DBusHandlerResult seat_message_handler(
173                 DBusConnection *connection,
174                 DBusMessage *message,
175                 void *userdata) {
176
177         Manager *m = userdata;
178         Seat *s;
179         int r;
180
181         r = get_seat_for_path(m, dbus_message_get_path(message), &s);
182         if (r < 0) {
183
184                 if (r == -ENOMEM)
185                         return DBUS_HANDLER_RESULT_NEED_MEMORY;
186
187                 if (r == -ENOENT) {
188                         DBusError e;
189
190                         dbus_error_init(&e);
191                         dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
192                         return bus_send_error_reply(connection, message, &e, r);
193                 }
194
195                 return bus_send_error_reply(connection, message, NULL, r);
196         }
197
198         return seat_message_dispatch(s, connection, message);
199 }
200
201 const DBusObjectPathVTable bus_seat_vtable = {
202         .message_function = seat_message_handler
203 };
204
205 char *seat_bus_path(Seat *s) {
206         char *t, *r;
207
208         assert(s);
209
210         t = bus_path_escape(s->id);
211         if (!t)
212                 return NULL;
213
214         r = strappend("/org/freedesktop/login1/seat/", t);
215         free(t);
216
217         return r;
218 }