blob: bfbd1b88c700208b19d70d9457f84c4acab5f82f [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "properties"
Igor Murashkind8f2a8d2014-04-08 11:22:42 -070018// #define LOG_NDEBUG 0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080019
20#include <stdlib.h>
21#include <string.h>
Igor Murashkind8f2a8d2014-04-08 11:22:42 -070022#include <ctype.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023#include <unistd.h>
24#include <cutils/sockets.h>
25#include <errno.h>
26#include <assert.h>
27
28#include <cutils/properties.h>
Igor Murashkind8f2a8d2014-04-08 11:22:42 -070029#include <stdbool.h>
30#include <inttypes.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080031#include "loghack.h"
32
Igor Murashkind8f2a8d2014-04-08 11:22:42 -070033int8_t property_get_bool(const char *key, int8_t default_value) {
34 if (!key) {
35 return default_value;
36 }
37
38 int8_t result = default_value;
39 char buf[PROPERTY_VALUE_MAX] = {'\0',};
40
41 int len = property_get(key, buf, "");
42 if (len == 1) {
43 char ch = buf[0];
44 if (ch == '0' || ch == 'n') {
45 result = false;
46 } else if (ch == '1' || ch == 'y') {
47 result = true;
48 }
49 } else if (len > 1) {
50 if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
51 result = false;
52 } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
53 result = true;
54 }
55 }
56
57 return result;
58}
59
60// Convert string property to int (default if fails); return default value if out of bounds
61static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
62 intmax_t default_value) {
63 if (!key) {
64 return default_value;
65 }
66
67 intmax_t result = default_value;
68 char buf[PROPERTY_VALUE_MAX] = {'\0',};
69 char *end = NULL;
70
71 int len = property_get(key, buf, "");
72 if (len > 0) {
73 int tmp = errno;
74 errno = 0;
75
76 // Infer base automatically
77 result = strtoimax(buf, &end, /*base*/0);
78 if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
79 // Over or underflow
80 result = default_value;
81 ALOGV("%s(%s,%lld) - overflow", __FUNCTION__, key, default_value);
82 } else if (result < lower_bound || result > upper_bound) {
83 // Out of range of requested bounds
84 result = default_value;
85 ALOGV("%s(%s,%lld) - out of range", __FUNCTION__, key, default_value);
86 } else if (end == buf) {
87 // Numeric conversion failed
88 result = default_value;
89 ALOGV("%s(%s,%lld) - numeric conversion failed", __FUNCTION__, key, default_value);
90 }
91
92 errno = tmp;
93 }
94
95 return result;
96}
97
98int64_t property_get_int64(const char *key, int64_t default_value) {
99 return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
100}
101
102int32_t property_get_int32(const char *key, int32_t default_value) {
103 return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
104}
105
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800106#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
107
108#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
109#include <sys/_system_properties.h>
110
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800111int property_set(const char *key, const char *value)
112{
Brad Fitzpatrickeb1f0c62011-03-07 13:52:21 -0800113 return __system_property_set(key, value);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800114}
115
116int property_get(const char *key, char *value, const char *default_value)
117{
118 int len;
119
120 len = __system_property_get(key, value);
121 if(len > 0) {
122 return len;
123 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800124 if(default_value) {
125 len = strlen(default_value);
Igor Murashkind8f2a8d2014-04-08 11:22:42 -0700126 if (len >= PROPERTY_VALUE_MAX) {
127 len = PROPERTY_VALUE_MAX - 1;
128 }
129 memcpy(value, default_value, len);
130 value[len] = '\0';
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 }
132 return len;
133}
134
Greg Hackmann69679352013-02-12 14:41:59 -0800135struct property_list_callback_data
136{
137 void (*propfn)(const char *key, const char *value, void *cookie);
138 void *cookie;
139};
140
141static void property_list_callback(const prop_info *pi, void *cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800142{
143 char name[PROP_NAME_MAX];
144 char value[PROP_VALUE_MAX];
Greg Hackmann69679352013-02-12 14:41:59 -0800145 struct property_list_callback_data *data = cookie;
146
147 __system_property_read(pi, name, value);
148 data->propfn(name, value, data->cookie);
149}
150
151int property_list(
152 void (*propfn)(const char *key, const char *value, void *cookie),
153 void *cookie)
154{
155 struct property_list_callback_data data = { propfn, cookie };
156 return __system_property_foreach(property_list_callback, &data);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800157}
158
159#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
160
161/*
162 * The Linux simulator provides a "system property server" that uses IPC
163 * to set/get/list properties. The file descriptor is shared by all
164 * threads in the process, so we use a mutex to ensure that requests
165 * from multiple threads don't get interleaved.
166 */
167#include <stdio.h>
168#include <sys/types.h>
169#include <sys/socket.h>
170#include <sys/un.h>
171#include <pthread.h>
172
173static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
174static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
175static int gPropFd = -1;
176
177/*
178 * Connect to the properties server.
179 *
180 * Returns the socket descriptor on success.
181 */
182static int connectToServer(const char* fileName)
183{
184 int sock = -1;
185 int cc;
186
187 struct sockaddr_un addr;
188
189 sock = socket(AF_UNIX, SOCK_STREAM, 0);
190 if (sock < 0) {
Steve Blockae8b56c2012-01-05 22:25:38 +0000191 ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800192 return -1;
193 }
194
195 /* connect to socket; fails if file doesn't exist */
196 strcpy(addr.sun_path, fileName); // max 108 bytes
197 addr.sun_family = AF_UNIX;
198 cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
199 if (cc < 0) {
200 // ENOENT means socket file doesn't exist
201 // ECONNREFUSED means socket exists but nobody is listening
Steve Blockae8b56c2012-01-05 22:25:38 +0000202 //ALOGW("AF_UNIX connect failed for '%s': %s\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800203 // fileName, strerror(errno));
204 close(sock);
205 return -1;
206 }
207
208 return sock;
209}
210
211/*
212 * Perform one-time initialization.
213 */
214static void init(void)
215{
216 assert(gPropFd == -1);
217
218 gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
219 if (gPropFd < 0) {
Steve Blockae8b56c2012-01-05 22:25:38 +0000220 //ALOGW("not connected to system property server\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800221 } else {
Steve Block69f4cd72011-10-20 11:54:09 +0100222 //ALOGV("Connected to system property server\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223 }
224}
225
226int property_get(const char *key, char *value, const char *default_value)
227{
228 char sendBuf[1+PROPERTY_KEY_MAX];
229 char recvBuf[1+PROPERTY_VALUE_MAX];
230 int len = -1;
231
Steve Block69f4cd72011-10-20 11:54:09 +0100232 //ALOGV("PROPERTY GET [%s]\n", key);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800233
234 pthread_once(&gInitOnce, init);
235 if (gPropFd < 0) {
236 /* this mimics the behavior of the device implementation */
237 if (default_value != NULL) {
238 strcpy(value, default_value);
239 len = strlen(value);
240 }
241 return len;
242 }
243
244 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
245
246 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
247
248 sendBuf[0] = (char) kSystemPropertyGet;
249 strcpy(sendBuf+1, key);
250
251 pthread_mutex_lock(&gPropertyFdLock);
252 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
253 pthread_mutex_unlock(&gPropertyFdLock);
254 return -1;
255 }
256 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
257 pthread_mutex_unlock(&gPropertyFdLock);
258 return -1;
259 }
260 pthread_mutex_unlock(&gPropertyFdLock);
261
262 /* first byte is 0 if value not defined, 1 if found */
263 if (recvBuf[0] == 0) {
264 if (default_value != NULL) {
265 strcpy(value, default_value);
266 len = strlen(value);
267 } else {
268 /*
269 * If the value isn't defined, hand back an empty string and
270 * a zero length, rather than a failure. This seems wrong,
271 * since you can't tell the difference between "undefined" and
272 * "defined but empty", but it's what the device does.
273 */
274 value[0] = '\0';
275 len = 0;
276 }
277 } else if (recvBuf[0] == 1) {
278 strcpy(value, recvBuf+1);
279 len = strlen(value);
280 } else {
Steve Block01dda202012-01-06 14:13:42 +0000281 ALOGE("Got strange response to property_get request (%d)\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800282 recvBuf[0]);
283 assert(0);
284 return -1;
285 }
Steve Block69f4cd72011-10-20 11:54:09 +0100286 //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800287 // recvBuf[0], default_value, len, key, value);
288
289 return len;
290}
291
292
293int property_set(const char *key, const char *value)
294{
295 char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
296 char recvBuf[1];
297 int result = -1;
298
Steve Block69f4cd72011-10-20 11:54:09 +0100299 //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800300
301 pthread_once(&gInitOnce, init);
302 if (gPropFd < 0)
303 return -1;
304
305 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
306 if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
307
308 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
309
310 sendBuf[0] = (char) kSystemPropertySet;
311 strcpy(sendBuf+1, key);
312 strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
313
314 pthread_mutex_lock(&gPropertyFdLock);
315 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
316 pthread_mutex_unlock(&gPropertyFdLock);
317 return -1;
318 }
319 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
320 pthread_mutex_unlock(&gPropertyFdLock);
321 return -1;
322 }
323 pthread_mutex_unlock(&gPropertyFdLock);
324
325 if (recvBuf[0] != 1)
326 return -1;
327 return 0;
328}
329
330int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
331 void *cookie)
332{
Steve Block69f4cd72011-10-20 11:54:09 +0100333 //ALOGV("PROPERTY LIST\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800334 pthread_once(&gInitOnce, init);
335 if (gPropFd < 0)
336 return -1;
337
338 return 0;
339}
340
341#else
342
343/* SUPER-cheesy place-holder implementation for Win32 */
344
345#include <cutils/threads.h>
346
347static mutex_t env_lock = MUTEX_INITIALIZER;
348
349int property_get(const char *key, char *value, const char *default_value)
350{
351 char ename[PROPERTY_KEY_MAX + 6];
352 char *p;
353 int len;
354
355 len = strlen(key);
356 if(len >= PROPERTY_KEY_MAX) return -1;
357 memcpy(ename, "PROP_", 5);
358 memcpy(ename + 5, key, len + 1);
359
360 mutex_lock(&env_lock);
361
362 p = getenv(ename);
363 if(p == 0) p = "";
364 len = strlen(p);
365 if(len >= PROPERTY_VALUE_MAX) {
366 len = PROPERTY_VALUE_MAX - 1;
367 }
368
369 if((len == 0) && default_value) {
370 len = strlen(default_value);
371 memcpy(value, default_value, len + 1);
372 } else {
373 memcpy(value, p, len);
374 value[len] = 0;
375 }
376
377 mutex_unlock(&env_lock);
378
379 return len;
380}
381
382
383int property_set(const char *key, const char *value)
384{
385 char ename[PROPERTY_KEY_MAX + 6];
386 char *p;
387 int len;
388 int r;
389
390 if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
391
392 len = strlen(key);
393 if(len >= PROPERTY_KEY_MAX) return -1;
394 memcpy(ename, "PROP_", 5);
395 memcpy(ename + 5, key, len + 1);
396
397 mutex_lock(&env_lock);
398#ifdef HAVE_MS_C_RUNTIME
399 {
400 char temp[256];
401 snprintf( temp, sizeof(temp), "%s=%s", ename, value);
402 putenv(temp);
403 r = 0;
404 }
405#else
406 r = setenv(ename, value, 1);
407#endif
408 mutex_unlock(&env_lock);
409
410 return r;
411}
412
413int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
414 void *cookie)
415{
416 return 0;
417}
418
419#endif