blob: b12879e47e4f17bfcc6933980aee38a6f9ce55ee [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>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037
38#include <sys/mman.h>
39
40#include <sys/socket.h>
41#include <sys/un.h>
42#include <sys/select.h>
Nick Kralevich32417fb2013-01-23 09:28:35 -080043#include <sys/stat.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#include <sys/types.h>
45#include <netinet/in.h>
satokec7e8cc2011-03-15 11:02:26 +090046#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047
48#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
49#include <sys/_system_properties.h>
50
51#include <sys/atomics.h>
Greg Hackmannf7511e32013-06-20 10:33:28 -070052#include <bionic_atomic_inline.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080053
Colin Cross5cf32de2013-01-23 23:07:06 -080054struct prop_area {
55 unsigned volatile count;
56 unsigned volatile serial;
57 unsigned magic;
58 unsigned version;
Colin Cross5cf32de2013-01-23 23:07:06 -080059 unsigned toc[1];
60};
61
62typedef struct prop_area prop_area;
63
64struct prop_info {
65 char name[PROP_NAME_MAX];
66 unsigned volatile serial;
67 char value[PROP_VALUE_MAX];
68};
69
70typedef struct prop_info prop_info;
71
satokec7e8cc2011-03-15 11:02:26 +090072static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
Greg Hackmanncb215a72013-02-13 14:41:48 -080073static char property_filename[PATH_MAX] = PROP_FILENAME;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080074
Greg Hackmanncb215a72013-02-13 14:41:48 -080075prop_area *__system_property_regions__[PA_REGION_COUNT] = { NULL, };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076
Nick Kralevich32417fb2013-01-23 09:28:35 -080077static int get_fd_from_env(void)
78{
79 char *env = getenv("ANDROID_PROPERTY_WORKSPACE");
80
81 if (!env) {
82 return -1;
83 }
84
85 return atoi(env);
86}
87
Greg Hackmanncb215a72013-02-13 14:41:48 -080088static int map_prop_region_rw(size_t region)
Colin Cross5cf32de2013-01-23 23:07:06 -080089{
Greg Hackmanncb215a72013-02-13 14:41:48 -080090 prop_area *pa;
91 int fd;
92 size_t offset = region * PA_SIZE;
93
94 if (__system_property_regions__[region]) {
95 return 0;
96 }
97
98 /* dev is a tmpfs that we can use to carve a shared workspace
99 * out of, so let's do that...
100 */
101 fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW, 0644);
102 if (fd < 0) {
103 if (errno == EACCES) {
104 /* for consistency with the case where the process has already
105 * mapped the page in and segfaults when trying to write to it
106 */
107 abort();
108 }
109 return -1;
110 }
111
112 if (ftruncate(fd, offset + PA_SIZE) < 0)
113 goto out;
114
115 pa = mmap(NULL, PA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
116 if(pa == MAP_FAILED)
117 goto out;
118
Colin Cross5cf32de2013-01-23 23:07:06 -0800119 memset(pa, 0, PA_SIZE);
120 pa->magic = PROP_AREA_MAGIC;
121 pa->version = PROP_AREA_VERSION;
122
123 /* plug into the lib property services */
Greg Hackmanncb215a72013-02-13 14:41:48 -0800124 __system_property_regions__[region] = pa;
125
126 close(fd);
127 return 0;
128
129out:
130 close(fd);
131 return -1;
Colin Cross5cf32de2013-01-23 23:07:06 -0800132}
133
Greg Hackmanncb215a72013-02-13 14:41:48 -0800134int __system_property_set_filename(const char *filename)
135{
136 size_t len = strlen(filename);
137 if (len >= sizeof(property_filename))
138 return -1;
139
140 strcpy(property_filename, filename);
141 return 0;
142}
143
144int __system_property_area_init()
145{
146 return map_prop_region_rw(0);
147}
148
149static int map_prop_region(size_t region)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150{
Nick Kralevich32417fb2013-01-23 09:28:35 -0800151 bool fromFile = true;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800152 bool swapped;
153 size_t offset = region * PA_SIZE;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800154 int result = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800155
Greg Hackmanncb215a72013-02-13 14:41:48 -0800156 if(__system_property_regions__[region]) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157 return 0;
158 }
159
Greg Hackmanncb215a72013-02-13 14:41:48 -0800160 int fd = open(property_filename, O_RDONLY | O_NOFOLLOW);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800161
162 if ((fd < 0) && (errno == ENOENT)) {
163 /*
164 * For backwards compatibility, if the file doesn't
165 * exist, we use the environment to get the file descriptor.
166 * For security reasons, we only use this backup if the kernel
167 * returns ENOENT. We don't want to use the backup if the kernel
168 * returns other errors such as ENOMEM or ENFILE, since it
169 * might be possible for an external program to trigger this
170 * condition.
171 */
172 fd = get_fd_from_env();
173 fromFile = false;
174 }
175
176 if (fd < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800177 return -1;
178 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800179
180 struct stat fd_stat;
181 if (fstat(fd, &fd_stat) < 0) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800182 goto cleanup;
183 }
184
185 if ((fd_stat.st_uid != 0)
186 || (fd_stat.st_gid != 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800187 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
188 || (fd_stat.st_size < offset + PA_SIZE) ) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800189 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800190 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800191
Greg Hackmanncb215a72013-02-13 14:41:48 -0800192 prop_area *pa = mmap(NULL, PA_SIZE, PROT_READ, MAP_SHARED, fd, offset);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800193
Nick Kralevich32417fb2013-01-23 09:28:35 -0800194 if (pa == MAP_FAILED) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800195 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800196 }
197
198 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800199 munmap(pa, PA_SIZE);
Nick Kralevichc16961b2013-01-25 13:07:31 -0800200 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201 }
202
Nick Kralevichc16961b2013-01-25 13:07:31 -0800203 result = 0;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800204 swapped = __sync_bool_compare_and_swap(&__system_property_regions__[region],
205 NULL, pa);
206 if (!swapped) {
207 /**
208 * In the event of a race either mapping is equally good, so
209 * the thread that lost can just throw its mapping away and proceed as
210 * normal.
211 */
212 munmap(pa, PA_SIZE);
213 }
Nick Kralevichc16961b2013-01-25 13:07:31 -0800214
215cleanup:
216 if (fromFile) {
217 close(fd);
218 }
219
220 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800221}
222
Greg Hackmanncb215a72013-02-13 14:41:48 -0800223int __system_properties_init()
224{
225 return map_prop_region(0);
226}
227
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800228int __system_property_foreach(
229 void (*propfn)(const prop_info *pi, void *cookie),
230 void *cookie)
231{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800232 size_t region;
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800233
Greg Hackmanncb215a72013-02-13 14:41:48 -0800234 for (region = 0; region < PA_REGION_COUNT; region++) {
235 prop_area *pa;
236 unsigned i;
237
238 int err = map_prop_region(region);
239 if (err < 0)
240 break;
241 pa = __system_property_regions__[region];
242
243 for (i = 0; i < pa->count; i++) {
244 unsigned entry = pa->toc[i];
245 prop_info *pi = TOC_TO_INFO(pa, entry);
246 propfn(pi, cookie);
247 }
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800248 }
249
250 return 0;
251}
252
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800253const prop_info *__system_property_find_nth(unsigned n)
254{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800255 size_t region = n / PA_COUNT_MAX;
256 prop_area *pa;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257
Greg Hackmanncb215a72013-02-13 14:41:48 -0800258 int err = map_prop_region(region);
259 if (err < 0)
260 return NULL;
261 pa = __system_property_regions__[region];
262
263 if((n % PA_COUNT_MAX) >= pa->count) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800264 return 0;
265 } else {
266 return TOC_TO_INFO(pa, pa->toc[n]);
267 }
268}
269
270const prop_info *__system_property_find(const char *name)
271{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272 unsigned len = strlen(name);
Greg Hackmanncb215a72013-02-13 14:41:48 -0800273 size_t region;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800274
Colin Cross5cf32de2013-01-23 23:07:06 -0800275 if (len >= PROP_NAME_MAX)
276 return 0;
277 if (len < 1)
278 return 0;
279
Greg Hackmanncb215a72013-02-13 14:41:48 -0800280 for (region = 0; region < PA_REGION_COUNT; region++) {
281 prop_area *pa;
282 unsigned count;
283 unsigned *toc;
284 prop_info *pi;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700285
Greg Hackmanncb215a72013-02-13 14:41:48 -0800286 int err = map_prop_region(region);
287 if (err < 0)
288 return 0;
289 pa = __system_property_regions__[region];
290 count = pa->count;
291 toc = pa->toc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800292
Greg Hackmanncb215a72013-02-13 14:41:48 -0800293 while(count--) {
294 unsigned entry = *toc++;
295 if(TOC_NAME_LEN(entry) != len) continue;
296
297 pi = TOC_TO_INFO(pa, entry);
298 if(memcmp(name, pi->name, len)) continue;
299
300 return pi;
301 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800302 }
303
304 return 0;
305}
306
307int __system_property_read(const prop_info *pi, char *name, char *value)
308{
309 unsigned serial, len;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700310
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800311 for(;;) {
312 serial = pi->serial;
313 while(SERIAL_DIRTY(serial)) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700314 __futex_wait((volatile void *)&pi->serial, serial, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800315 serial = pi->serial;
316 }
317 len = SERIAL_VALUE_LEN(serial);
318 memcpy(value, pi->value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700319 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800320 if(serial == pi->serial) {
321 if(name != 0) {
322 strcpy(name, pi->name);
323 }
324 return len;
325 }
326 }
327}
328
329int __system_property_get(const char *name, char *value)
330{
331 const prop_info *pi = __system_property_find(name);
332
333 if(pi != 0) {
334 return __system_property_read(pi, 0, value);
335 } else {
336 value[0] = 0;
337 return 0;
338 }
339}
340
satokec7e8cc2011-03-15 11:02:26 +0900341
342static int send_prop_msg(prop_msg *msg)
343{
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700344 struct pollfd pollfds[1];
satokec7e8cc2011-03-15 11:02:26 +0900345 struct sockaddr_un addr;
346 socklen_t alen;
347 size_t namelen;
348 int s;
349 int r;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700350 int result = -1;
satokec7e8cc2011-03-15 11:02:26 +0900351
352 s = socket(AF_LOCAL, SOCK_STREAM, 0);
353 if(s < 0) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700354 return result;
satokec7e8cc2011-03-15 11:02:26 +0900355 }
356
357 memset(&addr, 0, sizeof(addr));
358 namelen = strlen(property_service_socket);
359 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
360 addr.sun_family = AF_LOCAL;
361 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
362
Jens Gulinc20d0f32012-07-19 14:10:46 +0200363 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
satokec7e8cc2011-03-15 11:02:26 +0900364 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700365 return result;
satokec7e8cc2011-03-15 11:02:26 +0900366 }
367
368 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
369
370 if(r == sizeof(prop_msg)) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700371 // We successfully wrote to the property server but now we
372 // wait for the property server to finish its work. It
373 // acknowledges its completion by closing the socket so we
374 // poll here (on nothing), waiting for the socket to close.
375 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
376 // once the socket closes. Out of paranoia we cap our poll
377 // at 250 ms.
378 pollfds[0].fd = s;
379 pollfds[0].events = 0;
380 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
381 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
382 result = 0;
Brad Fitzpatrick8da75ab2011-04-01 10:53:12 -0700383 } else {
384 // Ignore the timeout and treat it like a success anyway.
385 // The init process is single-threaded and its property
386 // service is sometimes slow to respond (perhaps it's off
387 // starting a child process or something) and thus this
388 // times out and the caller thinks it failed, even though
389 // it's still getting around to it. So we fake it here,
390 // mostly for ctl.* properties, but we do try and wait 250
391 // ms so callers who do read-after-write can reliably see
392 // what they've written. Most of the time.
393 // TODO: fix the system properties design.
394 result = 0;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700395 }
satokec7e8cc2011-03-15 11:02:26 +0900396 }
397
398 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700399 return result;
satokec7e8cc2011-03-15 11:02:26 +0900400}
401
402int __system_property_set(const char *key, const char *value)
403{
satokec7e8cc2011-03-15 11:02:26 +0900404 int err;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700405 prop_msg msg;
satokec7e8cc2011-03-15 11:02:26 +0900406
407 if(key == 0) return -1;
408 if(value == 0) value = "";
409 if(strlen(key) >= PROP_NAME_MAX) return -1;
410 if(strlen(value) >= PROP_VALUE_MAX) return -1;
411
412 memset(&msg, 0, sizeof msg);
413 msg.cmd = PROP_MSG_SETPROP;
414 strlcpy(msg.name, key, sizeof msg.name);
415 strlcpy(msg.value, value, sizeof msg.value);
416
satokec7e8cc2011-03-15 11:02:26 +0900417 err = send_prop_msg(&msg);
418 if(err < 0) {
419 return err;
420 }
421
satokec7e8cc2011-03-15 11:02:26 +0900422 return 0;
423}
424
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800425int __system_property_wait(const prop_info *pi)
426{
427 unsigned n;
428 if(pi == 0) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800429 prop_area *pa = __system_property_regions__[0];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800430 n = pa->serial;
431 do {
432 __futex_wait(&pa->serial, n, 0);
433 } while(n == pa->serial);
434 } else {
435 n = pi->serial;
436 do {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700437 __futex_wait((volatile void *)&pi->serial, n, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800438 } while(n == pi->serial);
439 }
440 return 0;
441}
Colin Cross5cf32de2013-01-23 23:07:06 -0800442
443int __system_property_update(prop_info *pi, const char *value, unsigned int len)
444{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800445 prop_area *pa = __system_property_regions__[0];
Colin Cross5cf32de2013-01-23 23:07:06 -0800446
447 if (len >= PROP_VALUE_MAX)
448 return -1;
449
450 pi->serial = pi->serial | 1;
Greg Hackmannf7511e32013-06-20 10:33:28 -0700451 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800452 memcpy(pi->value, value, len + 1);
Greg Hackmannf7511e32013-06-20 10:33:28 -0700453 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800454 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
455 __futex_wake(&pi->serial, INT32_MAX);
456
457 pa->serial++;
458 __futex_wake(&pa->serial, INT32_MAX);
459
460 return 0;
461}
462
463int __system_property_add(const char *name, unsigned int namelen,
464 const char *value, unsigned int valuelen)
465{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800466 prop_area *pa;
467 prop_info *pa_info_array;
Colin Cross5cf32de2013-01-23 23:07:06 -0800468 prop_info *pi;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800469 size_t region;
Colin Cross5cf32de2013-01-23 23:07:06 -0800470
Colin Cross5cf32de2013-01-23 23:07:06 -0800471 if (namelen >= PROP_NAME_MAX)
472 return -1;
473 if (valuelen >= PROP_VALUE_MAX)
474 return -1;
475 if (namelen < 1)
476 return -1;
477
Greg Hackmanncb215a72013-02-13 14:41:48 -0800478 for (region = 0; region < PA_REGION_COUNT; region++)
479 {
480 int err = map_prop_region_rw(region);
481 if (err < 0)
482 return -1;
483
484 pa = __system_property_regions__[region];
485
486 if (pa->count < PA_COUNT_MAX)
487 break;
488 }
489
490 if (region == PA_REGION_COUNT)
491 return -1;
492
493 pa_info_array = (void*) (((char*) pa) + PA_INFO_START);
Colin Cross5cf32de2013-01-23 23:07:06 -0800494 pi = pa_info_array + pa->count;
495 pi->serial = (valuelen << 24);
496 memcpy(pi->name, name, namelen + 1);
497 memcpy(pi->value, value, valuelen + 1);
498
Greg Hackmanncb215a72013-02-13 14:41:48 -0800499 pa->toc[pa->count] = (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
Greg Hackmannf7511e32013-06-20 10:33:28 -0700500 ANDROID_MEMBAR_FULL();
Colin Cross5cf32de2013-01-23 23:07:06 -0800501
502 pa->count++;
503 pa->serial++;
504 __futex_wake(&pa->serial, INT32_MAX);
505
506 return 0;
507}
508
509unsigned int __system_property_serial(const prop_info *pi)
510{
511 return pi->serial;
512}
513
514unsigned int __system_property_wait_any(unsigned int serial)
515{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800516 prop_area *pa = __system_property_regions__[0];
Colin Cross5cf32de2013-01-23 23:07:06 -0800517
518 do {
519 __futex_wait(&pa->serial, serial, 0);
520 } while(pa->serial == serial);
521
522 return pa->serial;
523}