blob: f9671c6365998895a5f8518978cc56a9baf5b59e [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;
Colin Cross1d36ee12013-06-16 10:19:16 -0700131 int ret;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800132
133 /* dev is a tmpfs that we can use to carve a shared workspace
134 * out of, so let's do that...
135 */
Colin Cross1d36ee12013-06-16 10:19:16 -0700136 fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |
137 O_EXCL, 0444);
Greg Hackmanncb215a72013-02-13 14:41:48 -0800138 if (fd < 0) {
139 if (errno == EACCES) {
140 /* for consistency with the case where the process has already
141 * mapped the page in and segfaults when trying to write to it
142 */
143 abort();
144 }
145 return -1;
146 }
147
Colin Cross1d36ee12013-06-16 10:19:16 -0700148 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
149 if (ret < 0)
150 goto out;
151
Greg Hackmann1540f602013-06-19 13:31:21 -0700152 if (ftruncate(fd, PA_SIZE) < 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800153 goto out;
154
Greg Hackmann1540f602013-06-19 13:31:21 -0700155 pa = mmap(NULL, PA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Greg Hackmanncb215a72013-02-13 14:41:48 -0800156 if(pa == MAP_FAILED)
157 goto out;
158
Colin Cross5cf32de2013-01-23 23:07:06 -0800159 memset(pa, 0, PA_SIZE);
160 pa->magic = PROP_AREA_MAGIC;
161 pa->version = PROP_AREA_VERSION;
Greg Hackmann1540f602013-06-19 13:31:21 -0700162 /* reserve root node */
163 pa->bytes_used = sizeof(prop_bt);
Greg Hackmann996cdc42013-06-20 11:27:56 -0700164
Colin Cross5cf32de2013-01-23 23:07:06 -0800165 /* plug into the lib property services */
Greg Hackmann1540f602013-06-19 13:31:21 -0700166 __system_property_area__ = pa;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800167
168 close(fd);
169 return 0;
170
171out:
172 close(fd);
173 return -1;
Colin Cross5cf32de2013-01-23 23:07:06 -0800174}
175
Greg Hackmanncb215a72013-02-13 14:41:48 -0800176int __system_property_set_filename(const char *filename)
177{
178 size_t len = strlen(filename);
179 if (len >= sizeof(property_filename))
180 return -1;
181
182 strcpy(property_filename, filename);
183 return 0;
184}
185
186int __system_property_area_init()
187{
Greg Hackmann1540f602013-06-19 13:31:21 -0700188 return map_prop_area_rw();
Greg Hackmanncb215a72013-02-13 14:41:48 -0800189}
190
Greg Hackmann1540f602013-06-19 13:31:21 -0700191static int map_prop_area()
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800192{
Nick Kralevich32417fb2013-01-23 09:28:35 -0800193 bool fromFile = true;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800194 int result = -1;
Colin Cross1d36ee12013-06-16 10:19:16 -0700195 int fd;
196 int ret;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800197
Colin Cross1d36ee12013-06-16 10:19:16 -0700198 fd = open(property_filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
199 if (fd >= 0) {
200 /* For old kernels that don't support O_CLOEXEC */
201 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
202 if (ret < 0)
203 goto cleanup;
204 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800205
206 if ((fd < 0) && (errno == ENOENT)) {
207 /*
208 * For backwards compatibility, if the file doesn't
209 * exist, we use the environment to get the file descriptor.
210 * For security reasons, we only use this backup if the kernel
211 * returns ENOENT. We don't want to use the backup if the kernel
212 * returns other errors such as ENOMEM or ENFILE, since it
213 * might be possible for an external program to trigger this
214 * condition.
215 */
216 fd = get_fd_from_env();
217 fromFile = false;
218 }
219
220 if (fd < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800221 return -1;
222 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800223
224 struct stat fd_stat;
225 if (fstat(fd, &fd_stat) < 0) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800226 goto cleanup;
227 }
228
229 if ((fd_stat.st_uid != 0)
230 || (fd_stat.st_gid != 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800231 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
Greg Hackmann1540f602013-06-19 13:31:21 -0700232 || (fd_stat.st_size < PA_SIZE) ) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800233 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800234 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800235
Greg Hackmann1540f602013-06-19 13:31:21 -0700236 prop_area *pa = mmap(NULL, PA_SIZE, PROT_READ, MAP_SHARED, fd, 0);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800237
Nick Kralevich32417fb2013-01-23 09:28:35 -0800238 if (pa == MAP_FAILED) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800239 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800240 }
241
242 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800243 munmap(pa, PA_SIZE);
Nick Kralevichc16961b2013-01-25 13:07:31 -0800244 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800245 }
246
Nick Kralevichc16961b2013-01-25 13:07:31 -0800247 result = 0;
Greg Hackmann1540f602013-06-19 13:31:21 -0700248
249 __system_property_area__ = pa;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800250
251cleanup:
252 if (fromFile) {
253 close(fd);
254 }
255
256 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257}
258
Greg Hackmanncb215a72013-02-13 14:41:48 -0800259int __system_properties_init()
260{
Greg Hackmann1540f602013-06-19 13:31:21 -0700261 return map_prop_area();
Greg Hackmanncb215a72013-02-13 14:41:48 -0800262}
263
Greg Hackmann996cdc42013-06-20 11:27:56 -0700264static void *new_prop_obj(size_t size, prop_off_t *off)
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800265{
Greg Hackmann1540f602013-06-19 13:31:21 -0700266 prop_area *pa = __system_property_area__;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700267 size = ALIGN(size, sizeof(uint32_t));
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800268
Greg Hackmann1540f602013-06-19 13:31:21 -0700269 if (pa->bytes_used + size > PA_DATA_SIZE)
Greg Hackmann996cdc42013-06-20 11:27:56 -0700270 return NULL;
271
Greg Hackmann1540f602013-06-19 13:31:21 -0700272 *off = pa->bytes_used;
273 __system_property_area__->bytes_used += size;
274 return __system_property_area__->data + *off;
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800275}
276
Greg Hackmann996cdc42013-06-20 11:27:56 -0700277static 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 -0800278{
Greg Hackmann996cdc42013-06-20 11:27:56 -0700279 prop_off_t off_tmp;
280 prop_bt *bt = new_prop_obj(sizeof(prop_bt), &off_tmp);
281 if (bt) {
282 memcpy(bt->name, name, namelen);
283 bt->name[namelen] = '\0';
284 bt->namelen = namelen;
285 ANDROID_MEMBAR_FULL();
286 *off = off_tmp;
287 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800288
Greg Hackmann996cdc42013-06-20 11:27:56 -0700289 return bt;
290}
291
292static prop_info *new_prop_info(const char *name, uint8_t namelen,
293 const char *value, uint8_t valuelen, prop_off_t *off)
294{
295 prop_off_t off_tmp;
296 prop_info *info = new_prop_obj(sizeof(prop_info), &off_tmp);
297 if (info) {
298 memcpy(info->name, name, namelen);
299 info->name[namelen] = '\0';
300 info->serial = (valuelen << 24);
301 memcpy(info->value, value, valuelen);
302 info->value[valuelen] = '\0';
303 ANDROID_MEMBAR_FULL();
304 *off = off_tmp;
305 }
306
307 return info;
308}
309
310static void *to_prop_obj(prop_off_t off)
311{
Greg Hackmann1540f602013-06-19 13:31:21 -0700312 if (off > PA_DATA_SIZE)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800313 return NULL;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800314
Greg Hackmann1540f602013-06-19 13:31:21 -0700315 return __system_property_area__->data + off;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700316}
317
318static prop_bt *root_node()
319{
320 return to_prop_obj(0);
321}
322
323static int cmp_prop_name(const char *one, uint8_t one_len, const char *two,
324 uint8_t two_len)
325{
326 if (one_len < two_len)
327 return -1;
328 else if (one_len > two_len)
329 return 1;
330 else
331 return strncmp(one, two, one_len);
332}
333
334static prop_bt *find_prop_bt(prop_bt *bt, const char *name, uint8_t namelen,
335 bool alloc_if_needed)
336{
337 while (true) {
338 int ret;
339 if (!bt)
340 return bt;
341 ret = cmp_prop_name(name, namelen, bt->name, bt->namelen);
342
343 if (ret == 0) {
344 return bt;
345 } else if (ret < 0) {
346 if (bt->left) {
347 bt = to_prop_obj(bt->left);
348 } else {
349 if (!alloc_if_needed)
350 return NULL;
351
352 bt = new_prop_bt(name, namelen, &bt->left);
353 }
354 } else {
355 if (bt->right) {
356 bt = to_prop_obj(bt->right);
357 } else {
358 if (!alloc_if_needed)
359 return NULL;
360
361 bt = new_prop_bt(name, namelen, &bt->right);
362 }
363 }
364 }
365}
366
367static const prop_info *find_property(prop_bt *trie, const char *name,
368 uint8_t namelen, const char *value, uint8_t valuelen,
369 bool alloc_if_needed)
370{
371 const char *remaining_name = name;
372
373 while (true) {
374 char *sep = strchr(remaining_name, '.');
375 bool want_subtree = (sep != NULL);
376 uint8_t substr_size;
377
378 prop_bt *root;
379
380 if (want_subtree) {
381 substr_size = sep - remaining_name;
382 } else {
383 substr_size = strlen(remaining_name);
384 }
385
386 if (!substr_size)
387 return NULL;
388
389 if (trie->children) {
390 root = to_prop_obj(trie->children);
391 } else if (alloc_if_needed) {
392 root = new_prop_bt(remaining_name, substr_size, &trie->children);
393 } else {
394 root = NULL;
395 }
396
397 if (!root)
398 return NULL;
399
400 trie = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
401 if (!trie)
402 return NULL;
403
404 if (!want_subtree)
405 break;
406
407 remaining_name = sep + 1;
408 }
409
410 if (trie->prop) {
411 return to_prop_obj(trie->prop);
412 } else if (alloc_if_needed) {
413 return new_prop_info(name, namelen, value, valuelen, &trie->prop);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800414 } else {
Greg Hackmann996cdc42013-06-20 11:27:56 -0700415 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800416 }
417}
418
419const prop_info *__system_property_find(const char *name)
420{
Greg Hackmann996cdc42013-06-20 11:27:56 -0700421 return find_property(root_node(), name, strlen(name), NULL, 0, false);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800422}
423
424int __system_property_read(const prop_info *pi, char *name, char *value)
425{
426 unsigned serial, len;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700427
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800428 for(;;) {
429 serial = pi->serial;
430 while(SERIAL_DIRTY(serial)) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700431 __futex_wait((volatile void *)&pi->serial, serial, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800432 serial = pi->serial;
433 }
434 len = SERIAL_VALUE_LEN(serial);
435 memcpy(value, pi->value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700436 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800437 if(serial == pi->serial) {
438 if(name != 0) {
439 strcpy(name, pi->name);
440 }
441 return len;
442 }
443 }
444}
445
446int __system_property_get(const char *name, char *value)
447{
448 const prop_info *pi = __system_property_find(name);
449
450 if(pi != 0) {
451 return __system_property_read(pi, 0, value);
452 } else {
453 value[0] = 0;
454 return 0;
455 }
456}
457
satokec7e8cc2011-03-15 11:02:26 +0900458
459static int send_prop_msg(prop_msg *msg)
460{
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700461 struct pollfd pollfds[1];
satokec7e8cc2011-03-15 11:02:26 +0900462 struct sockaddr_un addr;
463 socklen_t alen;
464 size_t namelen;
465 int s;
466 int r;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700467 int result = -1;
satokec7e8cc2011-03-15 11:02:26 +0900468
469 s = socket(AF_LOCAL, SOCK_STREAM, 0);
470 if(s < 0) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700471 return result;
satokec7e8cc2011-03-15 11:02:26 +0900472 }
473
474 memset(&addr, 0, sizeof(addr));
475 namelen = strlen(property_service_socket);
476 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
477 addr.sun_family = AF_LOCAL;
478 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
479
Jens Gulinc20d0f32012-07-19 14:10:46 +0200480 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
satokec7e8cc2011-03-15 11:02:26 +0900481 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700482 return result;
satokec7e8cc2011-03-15 11:02:26 +0900483 }
484
485 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
486
487 if(r == sizeof(prop_msg)) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700488 // We successfully wrote to the property server but now we
489 // wait for the property server to finish its work. It
490 // acknowledges its completion by closing the socket so we
491 // poll here (on nothing), waiting for the socket to close.
492 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
493 // once the socket closes. Out of paranoia we cap our poll
494 // at 250 ms.
495 pollfds[0].fd = s;
496 pollfds[0].events = 0;
497 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
498 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
499 result = 0;
Brad Fitzpatrick8da75ab2011-04-01 10:53:12 -0700500 } else {
501 // Ignore the timeout and treat it like a success anyway.
502 // The init process is single-threaded and its property
503 // service is sometimes slow to respond (perhaps it's off
504 // starting a child process or something) and thus this
505 // times out and the caller thinks it failed, even though
506 // it's still getting around to it. So we fake it here,
507 // mostly for ctl.* properties, but we do try and wait 250
508 // ms so callers who do read-after-write can reliably see
509 // what they've written. Most of the time.
510 // TODO: fix the system properties design.
511 result = 0;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700512 }
satokec7e8cc2011-03-15 11:02:26 +0900513 }
514
515 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700516 return result;
satokec7e8cc2011-03-15 11:02:26 +0900517}
518
519int __system_property_set(const char *key, const char *value)
520{
satokec7e8cc2011-03-15 11:02:26 +0900521 int err;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700522 prop_msg msg;
satokec7e8cc2011-03-15 11:02:26 +0900523
524 if(key == 0) return -1;
525 if(value == 0) value = "";
526 if(strlen(key) >= PROP_NAME_MAX) return -1;
527 if(strlen(value) >= PROP_VALUE_MAX) return -1;
528
529 memset(&msg, 0, sizeof msg);
530 msg.cmd = PROP_MSG_SETPROP;
531 strlcpy(msg.name, key, sizeof msg.name);
532 strlcpy(msg.value, value, sizeof msg.value);
533
satokec7e8cc2011-03-15 11:02:26 +0900534 err = send_prop_msg(&msg);
535 if(err < 0) {
536 return err;
537 }
538
satokec7e8cc2011-03-15 11:02:26 +0900539 return 0;
540}
541
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800542int __system_property_wait(const prop_info *pi)
543{
544 unsigned n;
545 if(pi == 0) {
Greg Hackmann1540f602013-06-19 13:31:21 -0700546 prop_area *pa = __system_property_area__;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800547 n = pa->serial;
548 do {
549 __futex_wait(&pa->serial, n, 0);
550 } while(n == pa->serial);
551 } else {
552 n = pi->serial;
553 do {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700554 __futex_wait((volatile void *)&pi->serial, n, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800555 } while(n == pi->serial);
556 }
557 return 0;
558}
Colin Cross5cf32de2013-01-23 23:07:06 -0800559
560int __system_property_update(prop_info *pi, const char *value, unsigned int len)
561{
Greg Hackmann1540f602013-06-19 13:31:21 -0700562 prop_area *pa = __system_property_area__;
Colin Cross5cf32de2013-01-23 23:07:06 -0800563
564 if (len >= PROP_VALUE_MAX)
565 return -1;
566
567 pi->serial = pi->serial | 1;
Greg Hackmannf7511e32013-06-20 10:33:28 -0700568 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800569 memcpy(pi->value, value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700570 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800571 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
572 __futex_wake(&pi->serial, INT32_MAX);
573
574 pa->serial++;
575 __futex_wake(&pa->serial, INT32_MAX);
576
577 return 0;
578}
579
580int __system_property_add(const char *name, unsigned int namelen,
581 const char *value, unsigned int valuelen)
582{
Greg Hackmann1540f602013-06-19 13:31:21 -0700583 prop_area *pa = __system_property_area__;
Greg Hackmann996cdc42013-06-20 11:27:56 -0700584 const prop_info *pi;
Colin Cross5cf32de2013-01-23 23:07:06 -0800585
Colin Cross5cf32de2013-01-23 23:07:06 -0800586 if (namelen >= PROP_NAME_MAX)
587 return -1;
588 if (valuelen >= PROP_VALUE_MAX)
589 return -1;
590 if (namelen < 1)
591 return -1;
592
Greg Hackmann996cdc42013-06-20 11:27:56 -0700593 pi = find_property(root_node(), name, namelen, value, valuelen, true);
594 if (!pi)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800595 return -1;
596
Colin Cross5cf32de2013-01-23 23:07:06 -0800597 pa->serial++;
598 __futex_wake(&pa->serial, INT32_MAX);
Colin Cross5cf32de2013-01-23 23:07:06 -0800599 return 0;
600}
601
602unsigned int __system_property_serial(const prop_info *pi)
603{
604 return pi->serial;
605}
606
607unsigned int __system_property_wait_any(unsigned int serial)
608{
Greg Hackmann1540f602013-06-19 13:31:21 -0700609 prop_area *pa = __system_property_area__;
Colin Cross5cf32de2013-01-23 23:07:06 -0800610
611 do {
612 __futex_wait(&pa->serial, serial, 0);
613 } while(pa->serial == serial);
614
615 return pa->serial;
616}
Greg Hackmann996cdc42013-06-20 11:27:56 -0700617
618struct find_nth_cookie {
619 unsigned count;
620 unsigned n;
621 const prop_info *pi;
622};
623
624static void find_nth_fn(const prop_info *pi, void *ptr)
625{
626 struct find_nth_cookie *cookie = ptr;
627
628 if (cookie->n == cookie->count)
629 cookie->pi = pi;
630
631 cookie->count++;
632}
633
634const prop_info *__system_property_find_nth(unsigned n)
635{
636 struct find_nth_cookie cookie;
637 int err;
638
639 memset(&cookie, 0, sizeof(cookie));
640 cookie.n = n;
641
642 err = __system_property_foreach(find_nth_fn, &cookie);
643 if (err < 0)
644 return NULL;
645
646 return cookie.pi;
647}
648
649static int foreach_property(prop_off_t off,
650 void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
651{
652 prop_bt *trie = to_prop_obj(off);
653 if (!trie)
654 return -1;
655
656 if (trie->left) {
657 int err = foreach_property(trie->left, propfn, cookie);
658 if (err < 0)
659 return -1;
660 }
661 if (trie->prop) {
662 prop_info *info = to_prop_obj(trie->prop);
663 if (!info)
664 return -1;
665 propfn(info, cookie);
666 }
667 if (trie->children) {
668 int err = foreach_property(trie->children, propfn, cookie);
669 if (err < 0)
670 return -1;
671 }
672 if (trie->right) {
673 int err = foreach_property(trie->right, propfn, cookie);
674 if (err < 0)
675 return -1;
676 }
677
678 return 0;
679}
680
681int __system_property_foreach(void (*propfn)(const prop_info *pi, void *cookie),
682 void *cookie)
683{
684 return foreach_property(0, propfn, cookie);
685}