blob: b283658aa4d03952c69d14dd2fdeef56aada5b58 [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 Murashkind4507e92014-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 Murashkind4507e92014-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 Murashkind4507e92014-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 Murashkind4507e92014-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;
Igor Murashkin8efea952014-04-15 18:06:39 -070081 ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
Igor Murashkind4507e92014-04-08 11:22:42 -070082 } else if (result < lower_bound || result > upper_bound) {
83 // Out of range of requested bounds
84 result = default_value;
Igor Murashkin8efea952014-04-15 18:06:39 -070085 ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
Igor Murashkind4507e92014-04-08 11:22:42 -070086 } else if (end == buf) {
87 // Numeric conversion failed
88 result = default_value;
Igor Murashkin8efea952014-04-15 18:06:39 -070089 ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
90 __FUNCTION__, key, default_value);
Igor Murashkind4507e92014-04-08 11:22:42 -070091 }
92
93 errno = tmp;
94 }
95
96 return result;
97}
98
99int64_t property_get_int64(const char *key, int64_t default_value) {
100 return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
101}
102
103int32_t property_get_int32(const char *key, int32_t default_value) {
104 return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
105}
106
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
108
109#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
110#include <sys/_system_properties.h>
111
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800112int property_set(const char *key, const char *value)
113{
Brad Fitzpatrickeb1f0c62011-03-07 13:52:21 -0800114 return __system_property_set(key, value);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800115}
116
117int property_get(const char *key, char *value, const char *default_value)
118{
119 int len;
120
121 len = __system_property_get(key, value);
122 if(len > 0) {
123 return len;
124 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800125 if(default_value) {
126 len = strlen(default_value);
Igor Murashkind4507e92014-04-08 11:22:42 -0700127 if (len >= PROPERTY_VALUE_MAX) {
128 len = PROPERTY_VALUE_MAX - 1;
129 }
130 memcpy(value, default_value, len);
131 value[len] = '\0';
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800132 }
133 return len;
134}
135
Greg Hackmanne7bb1592013-02-12 14:41:59 -0800136struct property_list_callback_data
137{
138 void (*propfn)(const char *key, const char *value, void *cookie);
139 void *cookie;
140};
141
142static void property_list_callback(const prop_info *pi, void *cookie)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800143{
144 char name[PROP_NAME_MAX];
145 char value[PROP_VALUE_MAX];
Greg Hackmanne7bb1592013-02-12 14:41:59 -0800146 struct property_list_callback_data *data = cookie;
147
148 __system_property_read(pi, name, value);
149 data->propfn(name, value, data->cookie);
150}
151
152int property_list(
153 void (*propfn)(const char *key, const char *value, void *cookie),
154 void *cookie)
155{
156 struct property_list_callback_data data = { propfn, cookie };
157 return __system_property_foreach(property_list_callback, &data);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800158}
159
160#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
161
162/*
163 * The Linux simulator provides a "system property server" that uses IPC
164 * to set/get/list properties. The file descriptor is shared by all
165 * threads in the process, so we use a mutex to ensure that requests
166 * from multiple threads don't get interleaved.
167 */
168#include <stdio.h>
169#include <sys/types.h>
170#include <sys/socket.h>
171#include <sys/un.h>
172#include <pthread.h>
173
174static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
175static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
176static int gPropFd = -1;
177
178/*
179 * Connect to the properties server.
180 *
181 * Returns the socket descriptor on success.
182 */
183static int connectToServer(const char* fileName)
184{
185 int sock = -1;
186 int cc;
187
188 struct sockaddr_un addr;
189
190 sock = socket(AF_UNIX, SOCK_STREAM, 0);
191 if (sock < 0) {
Steve Blockae8b56c2012-01-05 22:25:38 +0000192 ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800193 return -1;
194 }
195
196 /* connect to socket; fails if file doesn't exist */
197 strcpy(addr.sun_path, fileName); // max 108 bytes
198 addr.sun_family = AF_UNIX;
199 cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
200 if (cc < 0) {
201 // ENOENT means socket file doesn't exist
202 // ECONNREFUSED means socket exists but nobody is listening
Steve Blockae8b56c2012-01-05 22:25:38 +0000203 //ALOGW("AF_UNIX connect failed for '%s': %s\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204 // fileName, strerror(errno));
205 close(sock);
206 return -1;
207 }
208
209 return sock;
210}
211
212/*
213 * Perform one-time initialization.
214 */
215static void init(void)
216{
217 assert(gPropFd == -1);
218
219 gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
220 if (gPropFd < 0) {
Steve Blockae8b56c2012-01-05 22:25:38 +0000221 //ALOGW("not connected to system property server\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222 } else {
Steve Block69f4cd72011-10-20 11:54:09 +0100223 //ALOGV("Connected to system property server\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224 }
225}
226
227int property_get(const char *key, char *value, const char *default_value)
228{
229 char sendBuf[1+PROPERTY_KEY_MAX];
230 char recvBuf[1+PROPERTY_VALUE_MAX];
231 int len = -1;
232
Steve Block69f4cd72011-10-20 11:54:09 +0100233 //ALOGV("PROPERTY GET [%s]\n", key);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234
235 pthread_once(&gInitOnce, init);
236 if (gPropFd < 0) {
237 /* this mimics the behavior of the device implementation */
238 if (default_value != NULL) {
239 strcpy(value, default_value);
240 len = strlen(value);
241 }
242 return len;
243 }
244
245 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
246
247 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
248
249 sendBuf[0] = (char) kSystemPropertyGet;
250 strcpy(sendBuf+1, key);
251
252 pthread_mutex_lock(&gPropertyFdLock);
253 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
254 pthread_mutex_unlock(&gPropertyFdLock);
255 return -1;
256 }
257 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
258 pthread_mutex_unlock(&gPropertyFdLock);
259 return -1;
260 }
261 pthread_mutex_unlock(&gPropertyFdLock);
262
263 /* first byte is 0 if value not defined, 1 if found */
264 if (recvBuf[0] == 0) {
265 if (default_value != NULL) {
266 strcpy(value, default_value);
267 len = strlen(value);
268 } else {
269 /*
270 * If the value isn't defined, hand back an empty string and
271 * a zero length, rather than a failure. This seems wrong,
272 * since you can't tell the difference between "undefined" and
273 * "defined but empty", but it's what the device does.
274 */
275 value[0] = '\0';
276 len = 0;
277 }
278 } else if (recvBuf[0] == 1) {
279 strcpy(value, recvBuf+1);
280 len = strlen(value);
281 } else {
Steve Block01dda202012-01-06 14:13:42 +0000282 ALOGE("Got strange response to property_get request (%d)\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800283 recvBuf[0]);
284 assert(0);
285 return -1;
286 }
Steve Block69f4cd72011-10-20 11:54:09 +0100287 //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288 // recvBuf[0], default_value, len, key, value);
289
290 return len;
291}
292
293
294int property_set(const char *key, const char *value)
295{
296 char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
297 char recvBuf[1];
298 int result = -1;
299
Steve Block69f4cd72011-10-20 11:54:09 +0100300 //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301
302 pthread_once(&gInitOnce, init);
303 if (gPropFd < 0)
304 return -1;
305
306 if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
307 if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
308
309 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind
310
311 sendBuf[0] = (char) kSystemPropertySet;
312 strcpy(sendBuf+1, key);
313 strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
314
315 pthread_mutex_lock(&gPropertyFdLock);
316 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
317 pthread_mutex_unlock(&gPropertyFdLock);
318 return -1;
319 }
320 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
321 pthread_mutex_unlock(&gPropertyFdLock);
322 return -1;
323 }
324 pthread_mutex_unlock(&gPropertyFdLock);
325
326 if (recvBuf[0] != 1)
327 return -1;
328 return 0;
329}
330
331int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
332 void *cookie)
333{
Steve Block69f4cd72011-10-20 11:54:09 +0100334 //ALOGV("PROPERTY LIST\n");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800335 pthread_once(&gInitOnce, init);
336 if (gPropFd < 0)
337 return -1;
338
339 return 0;
340}
341
342#else
343
344/* SUPER-cheesy place-holder implementation for Win32 */
345
346#include <cutils/threads.h>
347
348static mutex_t env_lock = MUTEX_INITIALIZER;
349
350int property_get(const char *key, char *value, const char *default_value)
351{
352 char ename[PROPERTY_KEY_MAX + 6];
353 char *p;
354 int len;
355
356 len = strlen(key);
357 if(len >= PROPERTY_KEY_MAX) return -1;
358 memcpy(ename, "PROP_", 5);
359 memcpy(ename + 5, key, len + 1);
360
361 mutex_lock(&env_lock);
362
363 p = getenv(ename);
364 if(p == 0) p = "";
365 len = strlen(p);
366 if(len >= PROPERTY_VALUE_MAX) {
367 len = PROPERTY_VALUE_MAX - 1;
368 }
369
370 if((len == 0) && default_value) {
371 len = strlen(default_value);
372 memcpy(value, default_value, len + 1);
373 } else {
374 memcpy(value, p, len);
375 value[len] = 0;
376 }
377
378 mutex_unlock(&env_lock);
379
380 return len;
381}
382
383
384int property_set(const char *key, const char *value)
385{
386 char ename[PROPERTY_KEY_MAX + 6];
387 char *p;
388 int len;
389 int r;
390
391 if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
392
393 len = strlen(key);
394 if(len >= PROPERTY_KEY_MAX) return -1;
395 memcpy(ename, "PROP_", 5);
396 memcpy(ename + 5, key, len + 1);
397
398 mutex_lock(&env_lock);
399#ifdef HAVE_MS_C_RUNTIME
400 {
401 char temp[256];
402 snprintf( temp, sizeof(temp), "%s=%s", ename, value);
403 putenv(temp);
404 r = 0;
405 }
406#else
407 r = setenv(ename, value, 1);
408#endif
409 mutex_unlock(&env_lock);
410
411 return r;
412}
413
414int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
415 void *cookie)
416{
417 return 0;
418}
419
420#endif