chiark / gitweb /
Fix service file to match installed elogind binary location
[elogind.git] / src / libelogind / sd-bus / bus-gvariant.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include "bus-gvariant.h"
21 #include "bus-signature.h"
22 #include "bus-type.h"
23
24 int bus_gvariant_get_size(const char *signature) {
25         const char *p;
26         int sum = 0, r;
27
28         /* For fixed size structs. Fails for variable size structs. */
29
30         p = signature;
31         while (*p != 0) {
32                 size_t n;
33
34                 r = signature_element_length(p, &n);
35                 if (r < 0)
36                         return r;
37                 else {
38                         char t[n+1];
39
40                         memcpy(t, p, n);
41                         t[n] = 0;
42
43                         r = bus_gvariant_get_alignment(t);
44                         if (r < 0)
45                                 return r;
46
47                         sum = ALIGN_TO(sum, r);
48                 }
49
50                 switch (*p) {
51
52                 case SD_BUS_TYPE_BOOLEAN:
53                 case SD_BUS_TYPE_BYTE:
54                         sum += 1;
55                         break;
56
57                 case SD_BUS_TYPE_INT16:
58                 case SD_BUS_TYPE_UINT16:
59                         sum += 2;
60                         break;
61
62                 case SD_BUS_TYPE_INT32:
63                 case SD_BUS_TYPE_UINT32:
64                 case SD_BUS_TYPE_UNIX_FD:
65                         sum += 4;
66                         break;
67
68                 case SD_BUS_TYPE_INT64:
69                 case SD_BUS_TYPE_UINT64:
70                 case SD_BUS_TYPE_DOUBLE:
71                         sum += 8;
72                         break;
73
74                 case SD_BUS_TYPE_STRUCT_BEGIN:
75                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
76                         if (n == 2) {
77                                 /* unary type () has fixed size of 1 */
78                                 r = 1;
79                         } else {
80                                 char t[n-1];
81
82                                 memcpy(t, p + 1, n - 2);
83                                 t[n - 2] = 0;
84
85                                 r = bus_gvariant_get_size(t);
86                                 if (r < 0)
87                                         return r;
88                         }
89
90                         sum += r;
91                         break;
92                 }
93
94                 case SD_BUS_TYPE_STRING:
95                 case SD_BUS_TYPE_OBJECT_PATH:
96                 case SD_BUS_TYPE_SIGNATURE:
97                 case SD_BUS_TYPE_ARRAY:
98                 case SD_BUS_TYPE_VARIANT:
99                         return -EINVAL;
100
101                 default:
102                         assert_not_reached("Unknown signature type");
103                 }
104
105                 p += n;
106         }
107
108         r = bus_gvariant_get_alignment(signature);
109         if (r < 0)
110                 return r;
111
112         return ALIGN_TO(sum, r);
113 }
114
115 int bus_gvariant_get_alignment(const char *signature) {
116         size_t alignment = 1;
117         const char *p;
118         int r;
119
120         p = signature;
121         while (*p != 0 && alignment < 8) {
122                 size_t n;
123                 int a;
124
125                 r = signature_element_length(p, &n);
126                 if (r < 0)
127                         return r;
128
129                 switch (*p) {
130
131                 case SD_BUS_TYPE_BYTE:
132                 case SD_BUS_TYPE_BOOLEAN:
133                 case SD_BUS_TYPE_STRING:
134                 case SD_BUS_TYPE_OBJECT_PATH:
135                 case SD_BUS_TYPE_SIGNATURE:
136                         a = 1;
137                         break;
138
139                 case SD_BUS_TYPE_INT16:
140                 case SD_BUS_TYPE_UINT16:
141                         a = 2;
142                         break;
143
144                 case SD_BUS_TYPE_INT32:
145                 case SD_BUS_TYPE_UINT32:
146                 case SD_BUS_TYPE_UNIX_FD:
147                         a = 4;
148                         break;
149
150                 case SD_BUS_TYPE_INT64:
151                 case SD_BUS_TYPE_UINT64:
152                 case SD_BUS_TYPE_DOUBLE:
153                 case SD_BUS_TYPE_VARIANT:
154                         a = 8;
155                         break;
156
157                 case SD_BUS_TYPE_ARRAY: {
158                         char t[n];
159
160                         memcpy(t, p + 1, n - 1);
161                         t[n - 1] = 0;
162
163                         a = bus_gvariant_get_alignment(t);
164                         break;
165                 }
166
167                 case SD_BUS_TYPE_STRUCT_BEGIN:
168                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
169                         char t[n-1];
170
171                         memcpy(t, p + 1, n - 2);
172                         t[n - 2] = 0;
173
174                         a = bus_gvariant_get_alignment(t);
175                         break;
176                 }
177
178                 default:
179                         assert_not_reached("Unknown signature type");
180                 }
181
182                 if (a < 0)
183                         return a;
184
185                 assert(a > 0 && a <= 8);
186                 if ((size_t) a > alignment)
187                         alignment = (size_t) a;
188
189                 p += n;
190         }
191
192         return alignment;
193 }
194
195 int bus_gvariant_is_fixed_size(const char *signature) {
196         const char *p;
197         int r;
198
199         assert(signature);
200
201         p = signature;
202         while (*p != 0) {
203                 size_t n;
204
205                 r = signature_element_length(p, &n);
206                 if (r < 0)
207                         return r;
208
209                 switch (*p) {
210
211                 case SD_BUS_TYPE_STRING:
212                 case SD_BUS_TYPE_OBJECT_PATH:
213                 case SD_BUS_TYPE_SIGNATURE:
214                 case SD_BUS_TYPE_ARRAY:
215                 case SD_BUS_TYPE_VARIANT:
216                         return 0;
217
218                 case SD_BUS_TYPE_BYTE:
219                 case SD_BUS_TYPE_BOOLEAN:
220                 case SD_BUS_TYPE_INT16:
221                 case SD_BUS_TYPE_UINT16:
222                 case SD_BUS_TYPE_INT32:
223                 case SD_BUS_TYPE_UINT32:
224                 case SD_BUS_TYPE_UNIX_FD:
225                 case SD_BUS_TYPE_INT64:
226                 case SD_BUS_TYPE_UINT64:
227                 case SD_BUS_TYPE_DOUBLE:
228                         break;
229
230                 case SD_BUS_TYPE_STRUCT_BEGIN:
231                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
232                         char t[n-1];
233
234                         memcpy(t, p + 1, n - 2);
235                         t[n - 2] = 0;
236
237                         r = bus_gvariant_is_fixed_size(t);
238                         if (r <= 0)
239                                 return r;
240                         break;
241                 }
242
243                 default:
244                         assert_not_reached("Unknown signature type");
245                 }
246
247                 p += n;
248         }
249
250         return true;
251 }
252
253 size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) {
254         if (sz + extra <= 0xFF)
255                 return 1;
256         else if (sz + extra*2 <= 0xFFFF)
257                 return 2;
258         else if (sz + extra*4 <= 0xFFFFFFFF)
259                 return 4;
260         else
261                 return 8;
262 }
263
264 size_t bus_gvariant_read_word_le(void *p, size_t sz) {
265         union {
266                 uint16_t u16;
267                 uint32_t u32;
268                 uint64_t u64;
269         } x;
270
271         assert(p);
272
273         if (sz == 1)
274                 return *(uint8_t*) p;
275
276         memcpy(&x, p, sz);
277
278         if (sz == 2)
279                 return le16toh(x.u16);
280         else if (sz == 4)
281                 return le32toh(x.u32);
282         else if (sz == 8)
283                 return le64toh(x.u64);
284
285         assert_not_reached("unknown word width");
286 }
287
288 void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) {
289         union {
290                 uint16_t u16;
291                 uint32_t u32;
292                 uint64_t u64;
293         } x;
294
295         assert(p);
296         assert(sz == 8 || (value < (1ULL << (sz*8))));
297
298         if (sz == 1) {
299                 *(uint8_t*) p = value;
300                 return;
301         } else if (sz == 2)
302                 x.u16 = htole16((uint16_t) value);
303         else if (sz == 4)
304                 x.u32 = htole32((uint32_t) value);
305         else if (sz == 8)
306                 x.u64 = htole64((uint64_t) value);
307         else
308                 assert_not_reached("unknown word width");
309
310         memcpy(p, &x, sz);
311 }