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