Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/openlaunchd
Path: blob/master/liblaunch/launch_data.c
374 views
1
/*
2
* Copyright (c) 2005-2012 Apple Inc. All rights reserved.
3
*
4
* @APPLE_APACHE_LICENSE_HEADER_START@
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
10
* http://www.apache.org/licenses/LICENSE-2.0
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*
18
* @APPLE_APACHE_LICENSE_HEADER_END@
19
*/
20
#include "launch.h"
21
#include "byteswap.h"
22
23
#include <assert.h>
24
#include <errno.h>
25
#include <stdlib.h>
26
#include <string.h>
27
28
/* NOTE: defined temporarily in liblaunch.c */
29
extern int _fd(int fd);
30
31
launch_data_t
32
launch_data_alloc(launch_data_type_t t)
33
{
34
launch_data_t d = calloc(1, sizeof(struct _launch_data));
35
assert(NULL != d);
36
37
if (d) {
38
d->type = t;
39
switch (t) {
40
case LAUNCH_DATA_DICTIONARY:
41
case LAUNCH_DATA_ARRAY:
42
d->_array = malloc(0);
43
break;
44
case LAUNCH_DATA_OPAQUE:
45
d->opaque = malloc(0);
46
default:
47
break;
48
}
49
}
50
51
return d;
52
}
53
54
launch_data_type_t
55
launch_data_get_type(launch_data_t d)
56
{
57
return d->type;
58
}
59
60
void
61
launch_data_free(launch_data_t d)
62
{
63
size_t i;
64
65
switch (d->type) {
66
case LAUNCH_DATA_DICTIONARY:
67
case LAUNCH_DATA_ARRAY:
68
for (i = 0; i < d->_array_cnt; i++) {
69
if (d->_array[i]) {
70
launch_data_free(d->_array[i]);
71
}
72
}
73
free(d->_array);
74
break;
75
case LAUNCH_DATA_STRING:
76
if (d->string)
77
free(d->string);
78
break;
79
case LAUNCH_DATA_OPAQUE:
80
if (d->opaque)
81
free(d->opaque);
82
break;
83
default:
84
break;
85
}
86
free(d);
87
}
88
89
size_t
90
launch_data_dict_get_count(launch_data_t dict)
91
{
92
return dict->_array_cnt / 2;
93
}
94
95
bool
96
launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
97
{
98
size_t i;
99
launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING);
100
101
launch_data_set_string(thekey, key);
102
103
for (i = 0; i < dict->_array_cnt; i += 2) {
104
if (!strcasecmp(key, dict->_array[i]->string)) {
105
launch_data_array_set_index(dict, thekey, i);
106
launch_data_array_set_index(dict, what, i + 1);
107
return true;
108
}
109
}
110
launch_data_array_set_index(dict, thekey, i);
111
launch_data_array_set_index(dict, what, i + 1);
112
return true;
113
}
114
115
launch_data_t
116
launch_data_dict_lookup(launch_data_t dict, const char *key)
117
{
118
size_t i;
119
120
if (LAUNCH_DATA_DICTIONARY != dict->type)
121
return NULL;
122
123
for (i = 0; i < dict->_array_cnt; i += 2) {
124
if (!strcasecmp(key, dict->_array[i]->string))
125
return dict->_array[i + 1];
126
}
127
128
return NULL;
129
}
130
131
bool
132
launch_data_dict_remove(launch_data_t dict, const char *key)
133
{
134
size_t i;
135
136
for (i = 0; i < dict->_array_cnt; i += 2) {
137
if (!strcasecmp(key, dict->_array[i]->string))
138
break;
139
}
140
if (i == dict->_array_cnt)
141
return false;
142
launch_data_free(dict->_array[i]);
143
launch_data_free(dict->_array[i + 1]);
144
memmove(dict->_array + i, dict->_array + i + 2, (dict->_array_cnt - (i + 2)) * sizeof(launch_data_t));
145
dict->_array_cnt -= 2;
146
return true;
147
}
148
149
void
150
launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
151
{
152
size_t i;
153
154
if (LAUNCH_DATA_DICTIONARY != dict->type) {
155
return;
156
}
157
158
for (i = 0; i < dict->_array_cnt; i += 2) {
159
cb(dict->_array[i + 1], dict->_array[i]->string, context);
160
}
161
}
162
163
bool
164
launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
165
{
166
if ((ind + 1) >= where->_array_cnt) {
167
where->_array = reallocf(where->_array, (ind + 1) * sizeof(launch_data_t));
168
memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t));
169
where->_array_cnt = ind + 1;
170
}
171
172
if (where->_array[ind]) {
173
launch_data_free(where->_array[ind]);
174
}
175
176
where->_array[ind] = what;
177
return true;
178
}
179
180
launch_data_t
181
launch_data_array_get_index(launch_data_t where, size_t ind)
182
{
183
if (LAUNCH_DATA_ARRAY != where->type || ind >= where->_array_cnt) {
184
return NULL;
185
} else {
186
return where->_array[ind];
187
}
188
}
189
190
launch_data_t
191
launch_data_array_pop_first(launch_data_t where)
192
{
193
launch_data_t r = NULL;
194
195
if (where->_array_cnt > 0) {
196
r = where->_array[0];
197
memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t));
198
where->_array_cnt--;
199
}
200
return r;
201
}
202
203
size_t
204
launch_data_array_get_count(launch_data_t where)
205
{
206
if (LAUNCH_DATA_ARRAY != where->type)
207
return 0;
208
return where->_array_cnt;
209
}
210
211
bool
212
launch_data_set_errno(launch_data_t d, int e)
213
{
214
d->err = e;
215
return true;
216
}
217
218
bool
219
launch_data_set_fd(launch_data_t d, int fd)
220
{
221
d->fd = fd;
222
return true;
223
}
224
225
bool
226
launch_data_set_integer(launch_data_t d, long long n)
227
{
228
d->number = n;
229
return true;
230
}
231
232
bool
233
launch_data_set_bool(launch_data_t d, bool b)
234
{
235
d->boolean = b;
236
return true;
237
}
238
239
bool
240
launch_data_set_real(launch_data_t d, double n)
241
{
242
d->float_num = n;
243
return true;
244
}
245
246
bool
247
launch_data_set_string(launch_data_t d, const char *s)
248
{
249
if (d->string)
250
free(d->string);
251
d->string = strdup(s);
252
if (d->string) {
253
d->string_len = strlen(d->string);
254
return true;
255
}
256
return false;
257
}
258
259
bool
260
launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
261
{
262
d->opaque_size = os;
263
if (d->opaque)
264
free(d->opaque);
265
d->opaque = malloc(os);
266
if (d->opaque) {
267
memcpy(d->opaque, o, os);
268
return true;
269
}
270
return false;
271
}
272
273
274
#if HAS_MACH
275
bool
276
launch_data_set_machport(launch_data_t d, mach_port_t p)
277
{
278
d->mp = p;
279
return true;
280
}
281
#endif
282
283
#define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
284
285
size_t
286
launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fd_cnt)
287
{
288
launch_data_t o_in_w = where;
289
size_t i, rsz, node_data_len = sizeof(struct _launch_data);
290
291
if (node_data_len > len) {
292
return 0;
293
}
294
295
where += node_data_len;
296
297
o_in_w->type = host2wire(d->type);
298
299
size_t pad_len = 0;
300
switch (d->type) {
301
case LAUNCH_DATA_INTEGER:
302
o_in_w->number = host2wire(d->number);
303
break;
304
case LAUNCH_DATA_REAL:
305
o_in_w->float_num = host2wire_f(d->float_num);
306
break;
307
case LAUNCH_DATA_BOOL:
308
o_in_w->boolean = host2wire(d->boolean);
309
break;
310
case LAUNCH_DATA_ERRNO:
311
o_in_w->err = host2wire(d->err);
312
break;
313
case LAUNCH_DATA_FD:
314
o_in_w->fd = host2wire(d->fd);
315
if (fd_where && d->fd != -1) {
316
fd_where[*fd_cnt] = d->fd;
317
(*fd_cnt)++;
318
}
319
break;
320
case LAUNCH_DATA_STRING:
321
o_in_w->string_len = host2wire(d->string_len);
322
node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1);
323
324
if (node_data_len > len) {
325
return 0;
326
}
327
memcpy(where, d->string, d->string_len + 1);
328
329
/* Zero padded data. */
330
pad_len = ROUND_TO_64BIT_WORD_SIZE(d->string_len + 1) - (d->string_len + 1);
331
bzero(where + d->string_len + 1, pad_len);
332
333
break;
334
case LAUNCH_DATA_OPAQUE:
335
o_in_w->opaque_size = host2wire(d->opaque_size);
336
node_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size);
337
if (node_data_len > len) {
338
return 0;
339
}
340
memcpy(where, d->opaque, d->opaque_size);
341
342
/* Zero padded data. */
343
pad_len = ROUND_TO_64BIT_WORD_SIZE(d->opaque_size) - d->opaque_size;
344
bzero(where + d->opaque_size, pad_len);
345
346
break;
347
case LAUNCH_DATA_DICTIONARY:
348
case LAUNCH_DATA_ARRAY:
349
o_in_w->_array_cnt = host2wire(d->_array_cnt);
350
node_data_len += d->_array_cnt * sizeof(uint64_t);
351
if (node_data_len > len) {
352
return 0;
353
}
354
355
where += d->_array_cnt * sizeof(uint64_t);
356
357
for (i = 0; i < d->_array_cnt; i++) {
358
rsz = launch_data_pack(d->_array[i], where, len - node_data_len, fd_where, fd_cnt);
359
if (rsz == 0) {
360
return 0;
361
}
362
where += rsz;
363
node_data_len += rsz;
364
}
365
break;
366
default:
367
break;
368
}
369
370
return node_data_len;
371
}
372
373
launch_data_t
374
launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset)
375
{
376
launch_data_t r = data + *data_offset;
377
size_t i, tmpcnt;
378
379
if ((data_size - *data_offset) < sizeof(struct _launch_data))
380
return NULL;
381
*data_offset += sizeof(struct _launch_data);
382
383
switch (wire2host(r->type)) {
384
case LAUNCH_DATA_DICTIONARY:
385
case LAUNCH_DATA_ARRAY:
386
tmpcnt = wire2host(r->_array_cnt);
387
if ((data_size - *data_offset) < (tmpcnt * sizeof(uint64_t))) {
388
errno = EAGAIN;
389
return NULL;
390
}
391
r->_array = data + *data_offset;
392
*data_offset += tmpcnt * sizeof(uint64_t);
393
for (i = 0; i < tmpcnt; i++) {
394
r->_array[i] = launch_data_unpack(data, data_size, fds, fd_cnt, data_offset, fdoffset);
395
if (r->_array[i] == NULL)
396
return NULL;
397
}
398
r->_array_cnt = tmpcnt;
399
break;
400
case LAUNCH_DATA_STRING:
401
tmpcnt = wire2host(r->string_len);
402
if ((data_size - *data_offset) < (tmpcnt + 1)) {
403
errno = EAGAIN;
404
return NULL;
405
}
406
r->string = data + *data_offset;
407
r->string_len = tmpcnt;
408
*data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt + 1);
409
break;
410
case LAUNCH_DATA_OPAQUE:
411
tmpcnt = wire2host(r->opaque_size);
412
if ((data_size - *data_offset) < tmpcnt) {
413
errno = EAGAIN;
414
return NULL;
415
}
416
r->opaque = data + *data_offset;
417
r->opaque_size = tmpcnt;
418
*data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt);
419
break;
420
case LAUNCH_DATA_FD:
421
if (r->fd != -1 && fd_cnt > *fdoffset) {
422
r->fd = _fd(fds[*fdoffset]);
423
*fdoffset += 1;
424
}
425
break;
426
case LAUNCH_DATA_INTEGER:
427
r->number = wire2host(r->number);
428
break;
429
case LAUNCH_DATA_REAL:
430
r->float_num = wire2host_f(r->float_num);
431
break;
432
case LAUNCH_DATA_BOOL:
433
r->boolean = wire2host(r->boolean);
434
break;
435
case LAUNCH_DATA_ERRNO:
436
r->err = wire2host(r->err);
437
#if HAS_MACH
438
case LAUNCH_DATA_MACHPORT:
439
break;
440
#endif
441
default:
442
errno = EINVAL;
443
return NULL;
444
break;
445
}
446
447
r->type = wire2host(r->type);
448
449
return r;
450
}
451
452