1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "bus-map-properties.h"
4 #include "alloc-util.h"
5 #include "strv.h"
6 #include "bus-message.h"
7
bus_map_id128(sd_bus * bus,const char * member,sd_bus_message * m,sd_bus_error * error,void * userdata)8 int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
9 sd_id128_t *p = userdata;
10 const void *v;
11 size_t n;
12 int r;
13
14 r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n);
15 if (r < 0)
16 return r;
17
18 if (n == 0)
19 *p = SD_ID128_NULL;
20 else if (n == 16)
21 memcpy((*p).bytes, v, n);
22 else
23 return -EINVAL;
24
25 return 0;
26 }
27
bus_map_strv_sort(sd_bus * bus,const char * member,sd_bus_message * m,sd_bus_error * error,void * userdata)28 int bus_map_strv_sort(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
29 _cleanup_strv_free_ char **l = NULL;
30 char ***p = userdata;
31 int r;
32
33 r = bus_message_read_strv_extend(m, &l);
34 if (r < 0)
35 return r;
36
37 r = strv_extend_strv(p, l, false);
38 if (r < 0)
39 return r;
40
41 strv_sort(*p);
42 return 0;
43 }
44
map_basic(sd_bus * bus,const char * member,sd_bus_message * m,unsigned flags,sd_bus_error * error,void * userdata)45 static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
46 char type;
47 int r;
48
49 r = sd_bus_message_peek_type(m, &type, NULL);
50 if (r < 0)
51 return r;
52
53 switch (type) {
54
55 case SD_BUS_TYPE_STRING:
56 case SD_BUS_TYPE_OBJECT_PATH: {
57 const char **p = userdata;
58 const char *s;
59
60 r = sd_bus_message_read_basic(m, type, &s);
61 if (r < 0)
62 return r;
63
64 if (isempty(s))
65 s = NULL;
66
67 if (flags & BUS_MAP_STRDUP)
68 return free_and_strdup((char **) userdata, s);
69
70 *p = s;
71 return 0;
72 }
73
74 case SD_BUS_TYPE_ARRAY: {
75 _cleanup_strv_free_ char **l = NULL;
76 char ***p = userdata;
77
78 r = bus_message_read_strv_extend(m, &l);
79 if (r < 0)
80 return r;
81
82 return strv_extend_strv(p, l, false);
83 }
84
85 case SD_BUS_TYPE_BOOLEAN: {
86 int b;
87
88 r = sd_bus_message_read_basic(m, type, &b);
89 if (r < 0)
90 return r;
91
92 if (flags & BUS_MAP_BOOLEAN_AS_BOOL)
93 *(bool*) userdata = b;
94 else
95 *(int*) userdata = b;
96
97 return 0;
98 }
99
100 case SD_BUS_TYPE_INT32:
101 case SD_BUS_TYPE_UINT32: {
102 uint32_t u, *p = userdata;
103
104 r = sd_bus_message_read_basic(m, type, &u);
105 if (r < 0)
106 return r;
107
108 *p = u;
109 return 0;
110 }
111
112 case SD_BUS_TYPE_INT64:
113 case SD_BUS_TYPE_UINT64: {
114 uint64_t t, *p = userdata;
115
116 r = sd_bus_message_read_basic(m, type, &t);
117 if (r < 0)
118 return r;
119
120 *p = t;
121 return 0;
122 }
123
124 case SD_BUS_TYPE_DOUBLE: {
125 double d, *p = userdata;
126
127 r = sd_bus_message_read_basic(m, type, &d);
128 if (r < 0)
129 return r;
130
131 *p = d;
132 return 0;
133 }}
134
135 return -EOPNOTSUPP;
136 }
137
bus_message_map_all_properties(sd_bus_message * m,const struct bus_properties_map * map,unsigned flags,sd_bus_error * error,void * userdata)138 int bus_message_map_all_properties(
139 sd_bus_message *m,
140 const struct bus_properties_map *map,
141 unsigned flags,
142 sd_bus_error *error,
143 void *userdata) {
144
145 int r;
146
147 assert(m);
148 assert(map);
149
150 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
151 if (r < 0)
152 return r;
153
154 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
155 const struct bus_properties_map *prop;
156 const char *member;
157 const char *contents;
158 void *v;
159 unsigned i;
160
161 r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
162 if (r < 0)
163 return r;
164
165 for (i = 0, prop = NULL; map[i].member; i++)
166 if (streq(map[i].member, member)) {
167 prop = &map[i];
168 break;
169 }
170
171 if (prop) {
172 r = sd_bus_message_peek_type(m, NULL, &contents);
173 if (r < 0)
174 return r;
175
176 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
177 if (r < 0)
178 return r;
179
180 v = (uint8_t *)userdata + prop->offset;
181 if (map[i].set)
182 r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
183 else
184 r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
185 if (r < 0)
186 return r;
187
188 r = sd_bus_message_exit_container(m);
189 if (r < 0)
190 return r;
191 } else {
192 r = sd_bus_message_skip(m, "v");
193 if (r < 0)
194 return r;
195 }
196
197 r = sd_bus_message_exit_container(m);
198 if (r < 0)
199 return r;
200 }
201 if (r < 0)
202 return r;
203
204 return sd_bus_message_exit_container(m);
205 }
206
bus_map_all_properties(sd_bus * bus,const char * destination,const char * path,const struct bus_properties_map * map,unsigned flags,sd_bus_error * error,sd_bus_message ** reply,void * userdata)207 int bus_map_all_properties(
208 sd_bus *bus,
209 const char *destination,
210 const char *path,
211 const struct bus_properties_map *map,
212 unsigned flags,
213 sd_bus_error *error,
214 sd_bus_message **reply,
215 void *userdata) {
216
217 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
218 int r;
219
220 assert(bus);
221 assert(destination);
222 assert(path);
223 assert(map);
224 assert(reply || (flags & BUS_MAP_STRDUP));
225
226 r = sd_bus_call_method(
227 bus,
228 destination,
229 path,
230 "org.freedesktop.DBus.Properties",
231 "GetAll",
232 error,
233 &m,
234 "s", "");
235 if (r < 0)
236 return r;
237
238 r = bus_message_map_all_properties(m, map, flags, error, userdata);
239 if (r < 0)
240 return r;
241
242 if (reply)
243 *reply = sd_bus_message_ref(m);
244
245 return r;
246 }
247