blob: 800c8b84fd4030cb5401f65b35099f1d320bb678 [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>
52
Colin Cross5cf32de2013-01-23 23:07:06 -080053struct prop_area {
54 unsigned volatile count;
55 unsigned volatile serial;
56 unsigned magic;
57 unsigned version;
Colin Cross5cf32de2013-01-23 23:07:06 -080058 unsigned toc[1];
59};
60
61typedef struct prop_area prop_area;
62
63struct prop_info {
64 char name[PROP_NAME_MAX];
65 unsigned volatile serial;
66 char value[PROP_VALUE_MAX];
67};
68
69typedef struct prop_info prop_info;
70
satokec7e8cc2011-03-15 11:02:26 +090071static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
Greg Hackmanncb215a72013-02-13 14:41:48 -080072static char property_filename[PATH_MAX] = PROP_FILENAME;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080073
Greg Hackmanncb215a72013-02-13 14:41:48 -080074prop_area *__system_property_regions__[PA_REGION_COUNT] = { NULL, };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075
Nick Kralevich32417fb2013-01-23 09:28:35 -080076static int get_fd_from_env(void)
77{
78 char *env = getenv("ANDROID_PROPERTY_WORKSPACE");
79
80 if (!env) {
81 return -1;
82 }
83
84 return atoi(env);
85}
86
Greg Hackmanncb215a72013-02-13 14:41:48 -080087static int map_prop_region_rw(size_t region)
Colin Cross5cf32de2013-01-23 23:07:06 -080088{
Greg Hackmanncb215a72013-02-13 14:41:48 -080089 prop_area *pa;
90 int fd;
91 size_t offset = region * PA_SIZE;
92
93 if (__system_property_regions__[region]) {
94 return 0;
95 }
96
97 /* dev is a tmpfs that we can use to carve a shared workspace
98 * out of, so let's do that...
99 */
100 fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW, 0644);
101 if (fd < 0) {
102 if (errno == EACCES) {
103 /* for consistency with the case where the process has already
104 * mapped the page in and segfaults when trying to write to it
105 */
106 abort();
107 }
108 return -1;
109 }
110
111 if (ftruncate(fd, offset + PA_SIZE) < 0)
112 goto out;
113
114 pa = mmap(NULL, PA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
115 if(pa == MAP_FAILED)
116 goto out;
117
Colin Cross5cf32de2013-01-23 23:07:06 -0800118 memset(pa, 0, PA_SIZE);
119 pa->magic = PROP_AREA_MAGIC;
120 pa->version = PROP_AREA_VERSION;
121
122 /* plug into the lib property services */
Greg Hackmanncb215a72013-02-13 14:41:48 -0800123 __system_property_regions__[region] = pa;
124
125 close(fd);
126 return 0;
127
128out:
129 close(fd);
130 return -1;
Colin Cross5cf32de2013-01-23 23:07:06 -0800131}
132
Greg Hackmanncb215a72013-02-13 14:41:48 -0800133int __system_property_set_filename(const char *filename)
134{
135 size_t len = strlen(filename);
136 if (len >= sizeof(property_filename))
137 return -1;
138
139 strcpy(property_filename, filename);
140 return 0;
141}
142
143int __system_property_area_init()
144{
145 return map_prop_region_rw(0);
146}
147
148static int map_prop_region(size_t region)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800149{
Nick Kralevich32417fb2013-01-23 09:28:35 -0800150 bool fromFile = true;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800151 bool swapped;
152 size_t offset = region * PA_SIZE;
Nick Kralevichc16961b2013-01-25 13:07:31 -0800153 int result = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800154
Greg Hackmanncb215a72013-02-13 14:41:48 -0800155 if(__system_property_regions__[region]) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800156 return 0;
157 }
158
Greg Hackmanncb215a72013-02-13 14:41:48 -0800159 int fd = open(property_filename, O_RDONLY | O_NOFOLLOW);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800160
161 if ((fd < 0) && (errno == ENOENT)) {
162 /*
163 * For backwards compatibility, if the file doesn't
164 * exist, we use the environment to get the file descriptor.
165 * For security reasons, we only use this backup if the kernel
166 * returns ENOENT. We don't want to use the backup if the kernel
167 * returns other errors such as ENOMEM or ENFILE, since it
168 * might be possible for an external program to trigger this
169 * condition.
170 */
171 fd = get_fd_from_env();
172 fromFile = false;
173 }
174
175 if (fd < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800176 return -1;
177 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800178
179 struct stat fd_stat;
180 if (fstat(fd, &fd_stat) < 0) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800181 goto cleanup;
182 }
183
184 if ((fd_stat.st_uid != 0)
185 || (fd_stat.st_gid != 0)
Greg Hackmanncb215a72013-02-13 14:41:48 -0800186 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
187 || (fd_stat.st_size < offset + PA_SIZE) ) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800188 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800189 }
Nick Kralevich32417fb2013-01-23 09:28:35 -0800190
Greg Hackmanncb215a72013-02-13 14:41:48 -0800191 prop_area *pa = mmap(NULL, PA_SIZE, PROT_READ, MAP_SHARED, fd, offset);
Nick Kralevich32417fb2013-01-23 09:28:35 -0800192
Nick Kralevich32417fb2013-01-23 09:28:35 -0800193 if (pa == MAP_FAILED) {
Nick Kralevichc16961b2013-01-25 13:07:31 -0800194 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800195 }
196
197 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800198 munmap(pa, PA_SIZE);
Nick Kralevichc16961b2013-01-25 13:07:31 -0800199 goto cleanup;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800200 }
201
Nick Kralevichc16961b2013-01-25 13:07:31 -0800202 result = 0;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800203 swapped = __sync_bool_compare_and_swap(&__system_property_regions__[region],
204 NULL, pa);
205 if (!swapped) {
206 /**
207 * In the event of a race either mapping is equally good, so
208 * the thread that lost can just throw its mapping away and proceed as
209 * normal.
210 */
211 munmap(pa, PA_SIZE);
212 }
Nick Kralevichc16961b2013-01-25 13:07:31 -0800213
214cleanup:
215 if (fromFile) {
216 close(fd);
217 }
218
219 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800220}
221
Greg Hackmanncb215a72013-02-13 14:41:48 -0800222int __system_properties_init()
223{
224 return map_prop_region(0);
225}
226
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800227int __system_property_foreach(
228 void (*propfn)(const prop_info *pi, void *cookie),
229 void *cookie)
230{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800231 size_t region;
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800232
Greg Hackmanncb215a72013-02-13 14:41:48 -0800233 for (region = 0; region < PA_REGION_COUNT; region++) {
234 prop_area *pa;
235 unsigned i;
236
237 int err = map_prop_region(region);
238 if (err < 0)
239 break;
240 pa = __system_property_regions__[region];
241
242 for (i = 0; i < pa->count; i++) {
243 unsigned entry = pa->toc[i];
244 prop_info *pi = TOC_TO_INFO(pa, entry);
245 propfn(pi, cookie);
246 }
Greg Hackmannc6ff8442013-02-12 16:39:31 -0800247 }
248
249 return 0;
250}
251
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252const prop_info *__system_property_find_nth(unsigned n)
253{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800254 size_t region = n / PA_COUNT_MAX;
255 prop_area *pa;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800256
Greg Hackmanncb215a72013-02-13 14:41:48 -0800257 int err = map_prop_region(region);
258 if (err < 0)
259 return NULL;
260 pa = __system_property_regions__[region];
261
262 if((n % PA_COUNT_MAX) >= pa->count) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800263 return 0;
264 } else {
265 return TOC_TO_INFO(pa, pa->toc[n]);
266 }
267}
268
269const prop_info *__system_property_find(const char *name)
270{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800271 unsigned len = strlen(name);
Greg Hackmanncb215a72013-02-13 14:41:48 -0800272 size_t region;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800273
Colin Cross5cf32de2013-01-23 23:07:06 -0800274 if (len >= PROP_NAME_MAX)
275 return 0;
276 if (len < 1)
277 return 0;
278
Greg Hackmanncb215a72013-02-13 14:41:48 -0800279 for (region = 0; region < PA_REGION_COUNT; region++) {
280 prop_area *pa;
281 unsigned count;
282 unsigned *toc;
283 prop_info *pi;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700284
Greg Hackmanncb215a72013-02-13 14:41:48 -0800285 int err = map_prop_region(region);
286 if (err < 0)
287 return 0;
288 pa = __system_property_regions__[region];
289 count = pa->count;
290 toc = pa->toc;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800291
Greg Hackmanncb215a72013-02-13 14:41:48 -0800292 while(count--) {
293 unsigned entry = *toc++;
294 if(TOC_NAME_LEN(entry) != len) continue;
295
296 pi = TOC_TO_INFO(pa, entry);
297 if(memcmp(name, pi->name, len)) continue;
298
299 return pi;
300 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800301 }
302
303 return 0;
304}
305
306int __system_property_read(const prop_info *pi, char *name, char *value)
307{
308 unsigned serial, len;
Elliott Hughes0d787c12013-04-04 13:46:46 -0700309
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800310 for(;;) {
311 serial = pi->serial;
312 while(SERIAL_DIRTY(serial)) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700313 __futex_wait((volatile void *)&pi->serial, serial, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800314 serial = pi->serial;
315 }
316 len = SERIAL_VALUE_LEN(serial);
317 memcpy(value, pi->value, len + 1);
318 if(serial == pi->serial) {
319 if(name != 0) {
320 strcpy(name, pi->name);
321 }
322 return len;
323 }
324 }
325}
326
327int __system_property_get(const char *name, char *value)
328{
329 const prop_info *pi = __system_property_find(name);
330
331 if(pi != 0) {
332 return __system_property_read(pi, 0, value);
333 } else {
334 value[0] = 0;
335 return 0;
336 }
337}
338
satokec7e8cc2011-03-15 11:02:26 +0900339
340static int send_prop_msg(prop_msg *msg)
341{
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700342 struct pollfd pollfds[1];
satokec7e8cc2011-03-15 11:02:26 +0900343 struct sockaddr_un addr;
344 socklen_t alen;
345 size_t namelen;
346 int s;
347 int r;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700348 int result = -1;
satokec7e8cc2011-03-15 11:02:26 +0900349
350 s = socket(AF_LOCAL, SOCK_STREAM, 0);
351 if(s < 0) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700352 return result;
satokec7e8cc2011-03-15 11:02:26 +0900353 }
354
355 memset(&addr, 0, sizeof(addr));
356 namelen = strlen(property_service_socket);
357 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
358 addr.sun_family = AF_LOCAL;
359 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
360
Jens Gulinc20d0f32012-07-19 14:10:46 +0200361 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
satokec7e8cc2011-03-15 11:02:26 +0900362 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700363 return result;
satokec7e8cc2011-03-15 11:02:26 +0900364 }
365
366 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
367
368 if(r == sizeof(prop_msg)) {
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700369 // We successfully wrote to the property server but now we
370 // wait for the property server to finish its work. It
371 // acknowledges its completion by closing the socket so we
372 // poll here (on nothing), waiting for the socket to close.
373 // If you 'adb shell setprop foo bar' you'll see the POLLHUP
374 // once the socket closes. Out of paranoia we cap our poll
375 // at 250 ms.
376 pollfds[0].fd = s;
377 pollfds[0].events = 0;
378 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
379 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
380 result = 0;
Brad Fitzpatrick8da75ab2011-04-01 10:53:12 -0700381 } else {
382 // Ignore the timeout and treat it like a success anyway.
383 // The init process is single-threaded and its property
384 // service is sometimes slow to respond (perhaps it's off
385 // starting a child process or something) and thus this
386 // times out and the caller thinks it failed, even though
387 // it's still getting around to it. So we fake it here,
388 // mostly for ctl.* properties, but we do try and wait 250
389 // ms so callers who do read-after-write can reliably see
390 // what they've written. Most of the time.
391 // TODO: fix the system properties design.
392 result = 0;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700393 }
satokec7e8cc2011-03-15 11:02:26 +0900394 }
395
396 close(s);
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700397 return result;
satokec7e8cc2011-03-15 11:02:26 +0900398}
399
400int __system_property_set(const char *key, const char *value)
401{
satokec7e8cc2011-03-15 11:02:26 +0900402 int err;
Brad Fitzpatrick23bc3ff2011-03-30 13:10:04 -0700403 prop_msg msg;
satokec7e8cc2011-03-15 11:02:26 +0900404
405 if(key == 0) return -1;
406 if(value == 0) value = "";
407 if(strlen(key) >= PROP_NAME_MAX) return -1;
408 if(strlen(value) >= PROP_VALUE_MAX) return -1;
409
410 memset(&msg, 0, sizeof msg);
411 msg.cmd = PROP_MSG_SETPROP;
412 strlcpy(msg.name, key, sizeof msg.name);
413 strlcpy(msg.value, value, sizeof msg.value);
414
satokec7e8cc2011-03-15 11:02:26 +0900415 err = send_prop_msg(&msg);
416 if(err < 0) {
417 return err;
418 }
419
satokec7e8cc2011-03-15 11:02:26 +0900420 return 0;
421}
422
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800423int __system_property_wait(const prop_info *pi)
424{
425 unsigned n;
426 if(pi == 0) {
Greg Hackmanncb215a72013-02-13 14:41:48 -0800427 prop_area *pa = __system_property_regions__[0];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800428 n = pa->serial;
429 do {
430 __futex_wait(&pa->serial, n, 0);
431 } while(n == pa->serial);
432 } else {
433 n = pi->serial;
434 do {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700435 __futex_wait((volatile void *)&pi->serial, n, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800436 } while(n == pi->serial);
437 }
438 return 0;
439}
Colin Cross5cf32de2013-01-23 23:07:06 -0800440
441int __system_property_update(prop_info *pi, const char *value, unsigned int len)
442{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800443 prop_area *pa = __system_property_regions__[0];
Colin Cross5cf32de2013-01-23 23:07:06 -0800444
445 if (len >= PROP_VALUE_MAX)
446 return -1;
447
448 pi->serial = pi->serial | 1;
449 memcpy(pi->value, value, len + 1);
450 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
451 __futex_wake(&pi->serial, INT32_MAX);
452
453 pa->serial++;
454 __futex_wake(&pa->serial, INT32_MAX);
455
456 return 0;
457}
458
459int __system_property_add(const char *name, unsigned int namelen,
460 const char *value, unsigned int valuelen)
461{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800462 prop_area *pa;
463 prop_info *pa_info_array;
Colin Cross5cf32de2013-01-23 23:07:06 -0800464 prop_info *pi;
Greg Hackmanncb215a72013-02-13 14:41:48 -0800465 size_t region;
Colin Cross5cf32de2013-01-23 23:07:06 -0800466
Colin Cross5cf32de2013-01-23 23:07:06 -0800467 if (namelen >= PROP_NAME_MAX)
468 return -1;
469 if (valuelen >= PROP_VALUE_MAX)
470 return -1;
471 if (namelen < 1)
472 return -1;
473
Greg Hackmanncb215a72013-02-13 14:41:48 -0800474 for (region = 0; region < PA_REGION_COUNT; region++)
475 {
476 int err = map_prop_region_rw(region);
477 if (err < 0)
478 return -1;
479
480 pa = __system_property_regions__[region];
481
482 if (pa->count < PA_COUNT_MAX)
483 break;
484 }
485
486 if (region == PA_REGION_COUNT)
487 return -1;
488
489 pa_info_array = (void*) (((char*) pa) + PA_INFO_START);
Colin Cross5cf32de2013-01-23 23:07:06 -0800490 pi = pa_info_array + pa->count;
491 pi->serial = (valuelen << 24);
492 memcpy(pi->name, name, namelen + 1);
493 memcpy(pi->value, value, valuelen + 1);
494
Greg Hackmanncb215a72013-02-13 14:41:48 -0800495 pa->toc[pa->count] = (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
Colin Cross5cf32de2013-01-23 23:07:06 -0800496
497 pa->count++;
498 pa->serial++;
499 __futex_wake(&pa->serial, INT32_MAX);
500
501 return 0;
502}
503
504unsigned int __system_property_serial(const prop_info *pi)
505{
506 return pi->serial;
507}
508
509unsigned int __system_property_wait_any(unsigned int serial)
510{
Greg Hackmanncb215a72013-02-13 14:41:48 -0800511 prop_area *pa = __system_property_regions__[0];
Colin Cross5cf32de2013-01-23 23:07:06 -0800512
513 do {
514 __futex_wait(&pa->serial, serial, 0);
515 } while(pa->serial == serial);
516
517 return pa->serial;
518}