blob: d4054d245805d4a0b9d7b7e67b2c60bc62aef6d0 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28#include <stdio.h>
Colin Cross5cf32de2013-01-23 23:07:06 -080029#include <stdint.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080030#include <stdlib.h>
31#include <unistd.h>
32#include <stddef.h>
33#include <errno.h>
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -070034#include <poll.h>
Nick Kralevich32417fb2013-01-23 09:28:35 -080035#include <fcntl.h>
36#include <stdbool.h>
Greg Hackmann996cdc42013-06-20 11:27:56 -070037#include <string.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038
39#include <sys/mman.h>
40
41#include <sys/socket.h>
42#include <sys/un.h>
43#include <sys/select.h>
Nick Kralevich32417fb2013-01-23 09:28:35 -080044#include <sys/stat.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080045#include <sys/types.h>
46#include <netinet/in.h>
satokec7e8cc2011-03-15 11:02:26 +090047#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048
49#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
50#include <sys/_system_properties.h>
51
52#include <sys/atomics.h>
Greg Hackmannf7511e32013-06-20 10:33:28 -070053#include <bionic_atomic_inline.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054
Greg Hackmann996cdc42013-06-20 11:27:56 -070055#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
56
Colin Cross5cf32de2013-01-23 23:07:06 -080057struct prop_area {
Greg Hackmann996cdc42013-06-20 11:27:56 -070058 unsigned bytes_used;
Colin Cross5cf32de2013-01-23 23:07:06 -080059 unsigned volatile serial;
60 unsigned magic;
61 unsigned version;
Greg Hackmann996cdc42013-06-20 11:27:56 -070062 unsigned reserved[28];
63 char data[0];
Colin Cross5cf32de2013-01-23 23:07:06 -080064};
65
66typedef struct prop_area prop_area;
67
68struct prop_info {
69 char name[PROP_NAME_MAX];
70 unsigned volatile serial;
71 char value[PROP_VALUE_MAX];
72};
73
74typedef struct prop_info prop_info;
75
Greg Hackmann996cdc42013-06-20 11:27:56 -070076/*
77 * Properties are stored in a hybrid trie/binary tree structure.
78 * Each property's name is delimited at '.' characters, and the tokens are put
79 * into a trie structure. Siblings at each level of the trie are stored in a
80 * binary tree. For instance, "ro.secure"="1" could be stored as follows:
81 *
82 * +-----+ children +----+ children +--------+
83 * | |-------------->| ro |-------------->| secure |
84 * +-----+ +----+ +--------+
85 * / \ / |
86 * left / \ right left / | prop +===========+
87 * v v v +-------->| ro.secure |
88 * +-----+ +-----+ +-----+ +-----------+
89 * | net | | sys | | com | | 1 |
90 * +-----+ +-----+ +-----+ +===========+
91 */
92
93typedef volatile uint32_t prop_off_t;
94struct prop_bt {
95 char name[PROP_NAME_MAX];
96 uint8_t namelen;
97 uint8_t reserved[3];
98
99 prop_off_t prop;
100
101 prop_off_t left;
102 prop_off_t right;
103
104 prop_off_t children;
105};
106
107typedef struct prop_bt prop_bt;
108
satokec7e8cc2011-03-15 11:02:26 +0900109static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800110static char property_filename[PATH_MAX] = PROP_FILENAME;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800111
Greg Hackmann1540f602013-06-19 13:31:21 -0700112prop_area *__system_property_area__ = NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113
Greg Hackmann996cdc42013-06-20 11:27:56 -0700114const size_t PA_DATA_SIZE = PA_SIZE - sizeof(prop_area);
115
Nick Kralevich32417fb2013-01-23 09:28:35 -0800116static int get_fd_from_env(void)
117{
118 char *env = getenv("ANDROID_PROPERTY_WORKSPACE");
119
120 if (!env) {
121 return -1;
122 }
123
124 return atoi(env);
125}
126
Greg Hackmann1540f602013-06-19 13:31:21 -0700127static int map_prop_area_rw()
Colin Cross5cf32de2013-01-23 23:07:06 -0800128{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800129 prop_area *pa;
130 int fd;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800131
132 /* dev is a tmpfs that we can use to carve a shared workspace
133 * out of, so let's do that...
134 */
135 fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW, 0644);
136 if (fd < 0) {
137 if (errno == EACCES) {
138 /* for consistency with the case where the process has already
139 * mapped the page in and segfaults when trying to write to it
140 */
141 abort();
142 }
143 return -1;
144 }
145
Greg Hackmann1540f602013-06-19 13:31:21 -0700146 if (ftruncate(fd, PA_SIZE) < 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800147 goto out;
148
Greg Hackmann1540f602013-06-19 13:31:21 -0700149 pa = mmap(NULL, PA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Greg Hackmanncb215a72013-02-13 14:41:48 -0800150 if(pa == MAP_FAILED)
151 goto out;
152
Colin Cross5cf32de2013-01-23 23:07:06 -0800153 memset(pa, 0, PA_SIZE);
154 pa->magic = PROP_AREA_MAGIC;
155 pa->version = PROP_AREA_VERSION;
Greg Hackmann1540f602013-06-19 13:31:21 -0700156 /* reserve root node */
157 pa->bytes_used = sizeof(prop_bt);
Greg Hackmann996cdc42013-06-20 11:27:56 -0700158
Colin Cross5cf32de2013-01-23 23:07:06 -0800159 /* plug into the lib property services */
Greg Hackmann1540f602013-06-19 13:31:21 -0700160 __system_property_area__ = pa;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800161
162 close(fd);
163 return 0;
164
165out:
166 close(fd);
167 return -1;
Colin Cross5cf32de2013-01-23 23:07:06 -0800168}
169
Greg Hackmanncb215a72013-02-13 14:41:48 -0800170int __system_property_set_filename(const char *filename)
171{
172 size_t len = strlen(filename);
173 if (len >= sizeof(property_filename))
174 return -1;
175
176 strcpy(property_filename, filename);
177 return 0;
178}
179
180int __system_property_area_init()
181{
Greg Hackmann1540f602013-06-19 13:31:21 -0700182 return map_prop_area_rw();
Greg Hackmanncb215a72013-02-13 14:41:48 -0800183}
184
Greg Hackmann1540f602013-06-19 13:31:21 -0700185static int map_prop_area()
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186{
Nick Kralevich32417fb2013-01-23 09:28:35 -0800187 bool fromFile = true;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800188 int result = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800189
Greg Hackmanncb215a72013-02-13 14:41:48 -0800190 int fd = open(property_filename, O_RDONLY | O_NOFOLLOW);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800191
192 if ((fd < 0) && (errno == ENOENT)) {
193 /*
194 * For backwards compatibility, if the file doesn't
195 * exist, we use the environment to get the file descriptor.
196 * For security reasons, we only use this backup if the kernel
197 * returns ENOENT. We don't want to use the backup if the kernel
198 * returns other errors such as ENOMEM or ENFILE, since it
199 * might be possible for an external program to trigger this
200 * condition.
201 */
202 fd = get_fd_from_env();
203 fromFile = false;
204 }
205
206 if (fd < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800207 return -1;
208 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800209
210 struct stat fd_stat;
211 if (fstat(fd, &fd_stat) < 0) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800212 goto cleanup;
213 }
214
215 if ((fd_stat.st_uid != 0)
216 || (fd_stat.st_gid != 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800217 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
Greg Hackmann1540f602013-06-19 13:31:21 -0700218 || (fd_stat.st_size < PA_SIZE) ) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800219 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800221
Greg Hackmann1540f602013-06-19 13:31:21 -0700222 prop_area *pa = mmap(NULL, PA_SIZE, PROT_READ, MAP_SHARED, fd, 0);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800223
Nick Kralevich32417fb2013-01-23 09:28:35 -0800224 if (pa == MAP_FAILED) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800225 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800226 }
227
228 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800229 munmap(pa, PA_SIZE);
Nick Kralevichc16961b2013-01-25 13:07:31 -0800230 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800231 }
232
Nick Kralevichc16961b2013-01-25 13:07:31 -0800233 result = 0;
Greg Hackmann1540f602013-06-19 13:31:21 -0700234
235 __system_property_area__ = pa;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800236
237cleanup:
238 if (fromFile) {
239 close(fd);
240 }
241
242 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800243}
244
Greg Hackmanncb215a72013-02-13 14:41:48 -0800245int __system_properties_init()
246{
Greg Hackmann1540f602013-06-19 13:31:21 -0700247 return map_prop_area();
Greg Hackmanncb215a72013-02-13 14:41:48 -0800248}
249
Greg Hackmann996cdc42013-06-20 11:27:56 -0700250static void *new_prop_obj(size_t size, prop_off_t *off)
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800251{
Greg Hackmann1540f602013-06-19 13:31:21 -0700252 prop_area *pa = __system_property_area__;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700253 size = ALIGN(size, sizeof(uint32_t));
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800254
Greg Hackmann1540f602013-06-19 13:31:21 -0700255 if (pa->bytes_used + size > PA_DATA_SIZE)
Greg Hackmann996cdc42013-06-20 11:27:56 -0700256 return NULL;
257
Greg Hackmann1540f602013-06-19 13:31:21 -0700258 *off = pa->bytes_used;
259 __system_property_area__->bytes_used += size;
260 return __system_property_area__->data + *off;
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800261}
262
Greg Hackmann996cdc42013-06-20 11:27:56 -0700263static prop_bt *new_prop_bt(const char *name, uint8_t namelen, prop_off_t *off)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800264{
Greg Hackmann996cdc42013-06-20 11:27:56 -0700265 prop_off_t off_tmp;
266 prop_bt *bt = new_prop_obj(sizeof(prop_bt), &off_tmp);
267 if (bt) {
268 memcpy(bt->name, name, namelen);
269 bt->name[namelen] = '\0';
270 bt->namelen = namelen;
271 ANDROID_MEMBAR_FULL();
272 *off = off_tmp;
273 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800274
Greg Hackmann996cdc42013-06-20 11:27:56 -0700275 return bt;
276}
277
278static prop_info *new_prop_info(const char *name, uint8_t namelen,
279 const char *value, uint8_t valuelen, prop_off_t *off)
280{
281 prop_off_t off_tmp;
282 prop_info *info = new_prop_obj(sizeof(prop_info), &off_tmp);
283 if (info) {
284 memcpy(info->name, name, namelen);
285 info->name[namelen] = '\0';
286 info->serial = (valuelen << 24);
287 memcpy(info->value, value, valuelen);
288 info->value[valuelen] = '\0';
289 ANDROID_MEMBAR_FULL();
290 *off = off_tmp;
291 }
292
293 return info;
294}
295
296static void *to_prop_obj(prop_off_t off)
297{
Greg Hackmann1540f602013-06-19 13:31:21 -0700298 if (off > PA_DATA_SIZE)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800299 return NULL;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800300
Greg Hackmann1540f602013-06-19 13:31:21 -0700301 return __system_property_area__->data + off;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700302}
303
304static prop_bt *root_node()
305{
306 return to_prop_obj(0);
307}
308
309static int cmp_prop_name(const char *one, uint8_t one_len, const char *two,
310 uint8_t two_len)
311{
312 if (one_len < two_len)
313 return -1;
314 else if (one_len > two_len)
315 return 1;
316 else
317 return strncmp(one, two, one_len);
318}
319
320static prop_bt *find_prop_bt(prop_bt *bt, const char *name, uint8_t namelen,
321 bool alloc_if_needed)
322{
323 while (true) {
324 int ret;
325 if (!bt)
326 return bt;
327 ret = cmp_prop_name(name, namelen, bt->name, bt->namelen);
328
329 if (ret == 0) {
330 return bt;
331 } else if (ret < 0) {
332 if (bt->left) {
333 bt = to_prop_obj(bt->left);
334 } else {
335 if (!alloc_if_needed)
336 return NULL;
337
338 bt = new_prop_bt(name, namelen, &bt->left);
339 }
340 } else {
341 if (bt->right) {
342 bt = to_prop_obj(bt->right);
343 } else {
344 if (!alloc_if_needed)
345 return NULL;
346
347 bt = new_prop_bt(name, namelen, &bt->right);
348 }
349 }
350 }
351}
352
353static const prop_info *find_property(prop_bt *trie, const char *name,
354 uint8_t namelen, const char *value, uint8_t valuelen,
355 bool alloc_if_needed)
356{
357 const char *remaining_name = name;
358
359 while (true) {
360 char *sep = strchr(remaining_name, '.');
361 bool want_subtree = (sep != NULL);
362 uint8_t substr_size;
363
364 prop_bt *root;
365
366 if (want_subtree) {
367 substr_size = sep - remaining_name;
368 } else {
369 substr_size = strlen(remaining_name);
370 }
371
372 if (!substr_size)
373 return NULL;
374
375 if (trie->children) {
376 root = to_prop_obj(trie->children);
377 } else if (alloc_if_needed) {
378 root = new_prop_bt(remaining_name, substr_size, &trie->children);
379 } else {
380 root = NULL;
381 }
382
383 if (!root)
384 return NULL;
385
386 trie = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
387 if (!trie)
388 return NULL;
389
390 if (!want_subtree)
391 break;
392
393 remaining_name = sep + 1;
394 }
395
396 if (trie->prop) {
397 return to_prop_obj(trie->prop);
398 } else if (alloc_if_needed) {
399 return new_prop_info(name, namelen, value, valuelen, &trie->prop);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800400 } else {
Greg Hackmann996cdc42013-06-20 11:27:56 -0700401 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800402 }
403}
404
405const prop_info *__system_property_find(const char *name)
406{
Greg Hackmann996cdc42013-06-20 11:27:56 -0700407 return find_property(root_node(), name, strlen(name), NULL, 0, false);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800408}
409
410int __system_property_read(const prop_info *pi, char *name, char *value)
411{
412 unsigned serial, len;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700413
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800414 for(;;) {
415 serial = pi->serial;
416 while(SERIAL_DIRTY(serial)) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700417 __futex_wait((volatile void *)&pi->serial, serial, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800418 serial = pi->serial;
419 }
420 len = SERIAL_VALUE_LEN(serial);
421 memcpy(value, pi->value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700422 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800423 if(serial == pi->serial) {
424 if(name != 0) {
425 strcpy(name, pi->name);
426 }
427 return len;
428 }
429 }
430}
431
432int __system_property_get(const char *name, char *value)
433{
434 const prop_info *pi = __system_property_find(name);
435
436 if(pi != 0) {
437 return __system_property_read(pi, 0, value);
438 } else {
439 value[0] = 0;
440 return 0;
441 }
442}
443
satokec7e8cc2011-03-15 11:02:26 +0900444
445static int send_prop_msg(prop_msg *msg)
446{
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700447 struct pollfd pollfds[1];
satokec7e8cc2011-03-15 11:02:26 +0900448 struct sockaddr_un addr;
449 socklen_t alen;
450 size_t namelen;
451 int s;
452 int r;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700453 int result = -1;
satokec7e8cc2011-03-15 11:02:26 +0900454
455 s = socket(AF_LOCAL, SOCK_STREAM, 0);
456 if(s < 0) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700457 return result;
satokec7e8cc2011-03-15 11:02:26 +0900458 }
459
460 memset(&addr, 0, sizeof(addr));
461 namelen = strlen(property_service_socket);
462 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
463 addr.sun_family = AF_LOCAL;
464 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
465
Jens Gulinc20d0f32012-07-19 14:10:46 +0200466 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
satokec7e8cc2011-03-15 11:02:26 +0900467 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700468 return result;
satokec7e8cc2011-03-15 11:02:26 +0900469 }
470
471 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
472
473 if(r == sizeof(prop_msg)) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700474 // We successfully wrote to the property server but now we
475 // wait for the property server to finish its work. It
476 // acknowledges its completion by closing the socket so we
477 // poll here (on nothing), waiting for the socket to close.
478 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
479 // once the socket closes. Out of paranoia we cap our poll
480 // at 250 ms.
481 pollfds[0].fd = s;
482 pollfds[0].events = 0;
483 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
484 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
485 result = 0;
Brad Fitzpatrick8da75ab2011-04-01 10:53:12 -0700486 } else {
487 // Ignore the timeout and treat it like a success anyway.
488 // The init process is single-threaded and its property
489 // service is sometimes slow to respond (perhaps it's off
490 // starting a child process or something) and thus this
491 // times out and the caller thinks it failed, even though
492 // it's still getting around to it. So we fake it here,
493 // mostly for ctl.* properties, but we do try and wait 250
494 // ms so callers who do read-after-write can reliably see
495 // what they've written. Most of the time.
496 // TODO: fix the system properties design.
497 result = 0;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700498 }
satokec7e8cc2011-03-15 11:02:26 +0900499 }
500
501 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700502 return result;
satokec7e8cc2011-03-15 11:02:26 +0900503}
504
505int __system_property_set(const char *key, const char *value)
506{
satokec7e8cc2011-03-15 11:02:26 +0900507 int err;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700508 prop_msg msg;
satokec7e8cc2011-03-15 11:02:26 +0900509
510 if(key == 0) return -1;
511 if(value == 0) value = "";
512 if(strlen(key) >= PROP_NAME_MAX) return -1;
513 if(strlen(value) >= PROP_VALUE_MAX) return -1;
514
515 memset(&msg, 0, sizeof msg);
516 msg.cmd = PROP_MSG_SETPROP;
517 strlcpy(msg.name, key, sizeof msg.name);
518 strlcpy(msg.value, value, sizeof msg.value);
519
satokec7e8cc2011-03-15 11:02:26 +0900520 err = send_prop_msg(&msg);
521 if(err < 0) {
522 return err;
523 }
524
satokec7e8cc2011-03-15 11:02:26 +0900525 return 0;
526}
527
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800528int __system_property_wait(const prop_info *pi)
529{
530 unsigned n;
531 if(pi == 0) {
Greg Hackmann1540f602013-06-19 13:31:21 -0700532 prop_area *pa = __system_property_area__;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800533 n = pa->serial;
534 do {
535 __futex_wait(&pa->serial, n, 0);
536 } while(n == pa->serial);
537 } else {
538 n = pi->serial;
539 do {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700540 __futex_wait((volatile void *)&pi->serial, n, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800541 } while(n == pi->serial);
542 }
543 return 0;
544}
Colin Cross5cf32de2013-01-23 23:07:06 -0800545
546int __system_property_update(prop_info *pi, const char *value, unsigned int len)
547{
Greg Hackmann1540f602013-06-19 13:31:21 -0700548 prop_area *pa = __system_property_area__;
Colin Cross5cf32de2013-01-23 23:07:06 -0800549
550 if (len >= PROP_VALUE_MAX)
551 return -1;
552
553 pi->serial = pi->serial | 1;
Greg Hackmannf7511e32013-06-20 10:33:28 -0700554 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800555 memcpy(pi->value, value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700556 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800557 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
558 __futex_wake(&pi->serial, INT32_MAX);
559
560 pa->serial++;
561 __futex_wake(&pa->serial, INT32_MAX);
562
563 return 0;
564}
565
566int __system_property_add(const char *name, unsigned int namelen,
567 const char *value, unsigned int valuelen)
568{
Greg Hackmann1540f602013-06-19 13:31:21 -0700569 prop_area *pa = __system_property_area__;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700570 const prop_info *pi;
Colin Cross5cf32de2013-01-23 23:07:06 -0800571
Colin Cross5cf32de2013-01-23 23:07:06 -0800572 if (namelen >= PROP_NAME_MAX)
573 return -1;
574 if (valuelen >= PROP_VALUE_MAX)
575 return -1;
576 if (namelen < 1)
577 return -1;
578
Greg Hackmann996cdc42013-06-20 11:27:56 -0700579 pi = find_property(root_node(), name, namelen, value, valuelen, true);
580 if (!pi)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800581 return -1;
582
Colin Cross5cf32de2013-01-23 23:07:06 -0800583 pa->serial++;
584 __futex_wake(&pa->serial, INT32_MAX);
Colin Cross5cf32de2013-01-23 23:07:06 -0800585 return 0;
586}
587
588unsigned int __system_property_serial(const prop_info *pi)
589{
590 return pi->serial;
591}
592
593unsigned int __system_property_wait_any(unsigned int serial)
594{
Greg Hackmann1540f602013-06-19 13:31:21 -0700595 prop_area *pa = __system_property_area__;
Colin Cross5cf32de2013-01-23 23:07:06 -0800596
597 do {
598 __futex_wait(&pa->serial, serial, 0);
599 } while(pa->serial == serial);
600
601 return pa->serial;
602}
Greg Hackmann996cdc42013-06-20 11:27:56 -0700603
604struct find_nth_cookie {
605 unsigned count;
606 unsigned n;
607 const prop_info *pi;
608};
609
610static void find_nth_fn(const prop_info *pi, void *ptr)
611{
612 struct find_nth_cookie *cookie = ptr;
613
614 if (cookie->n == cookie->count)
615 cookie->pi = pi;
616
617 cookie->count++;
618}
619
620const prop_info *__system_property_find_nth(unsigned n)
621{
622 struct find_nth_cookie cookie;
623 int err;
624
625 memset(&cookie, 0, sizeof(cookie));
626 cookie.n = n;
627
628 err = __system_property_foreach(find_nth_fn, &cookie);
629 if (err < 0)
630 return NULL;
631
632 return cookie.pi;
633}
634
635static int foreach_property(prop_off_t off,
636 void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
637{
638 prop_bt *trie = to_prop_obj(off);
639 if (!trie)
640 return -1;
641
642 if (trie->left) {
643 int err = foreach_property(trie->left, propfn, cookie);
644 if (err < 0)
645 return -1;
646 }
647 if (trie->prop) {
648 prop_info *info = to_prop_obj(trie->prop);
649 if (!info)
650 return -1;
651 propfn(info, cookie);
652 }
653 if (trie->children) {
654 int err = foreach_property(trie->children, propfn, cookie);
655 if (err < 0)
656 return -1;
657 }
658 if (trie->right) {
659 int err = foreach_property(trie->right, propfn, cookie);
660 if (err < 0)
661 return -1;
662 }
663
664 return 0;
665}
666
667int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
668 void *cookie)
669{
670 return foreach_property(0, propfn, cookie);
671}