1 /* 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" 18 // #define LOG_NDEBUG 0 19 20 #include <stdlib.h> 21 #include <string.h> 22 #include <ctype.h> 23 #include <unistd.h> 24 #include <cutils/sockets.h> 25 #include <errno.h> 26 #include <assert.h> 27 28 #include <cutils/properties.h> 29 #include <stdbool.h> 30 #include <inttypes.h> 31 #include "loghack.h" 32 33 int8_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 61 static 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,%" PRIdMAX ") - 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,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value); 86 } else if (end == buf) { 87 // Numeric conversion failed 88 result = default_value; 89 ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", 90 __FUNCTION__, key, default_value); 91 } 92 93 errno = tmp; 94 } 95 96 return result; 97 } 98 99 int64_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 103 int32_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 107 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES 108 109 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 110 #include <sys/_system_properties.h> 111 112 int property_set(const char *key, const char *value) 113 { 114 return __system_property_set(key, value); 115 } 116 117 int 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 } 125 if(default_value) { 126 len = strlen(default_value); 127 if (len >= PROPERTY_VALUE_MAX) { 128 len = PROPERTY_VALUE_MAX - 1; 129 } 130 memcpy(value, default_value, len); 131 value[len] = '\0'; 132 } 133 return len; 134 } 135 136 struct property_list_callback_data 137 { 138 void (*propfn)(const char *key, const char *value, void *cookie); 139 void *cookie; 140 }; 141 142 static void property_list_callback(const prop_info *pi, void *cookie) 143 { 144 char name[PROP_NAME_MAX]; 145 char value[PROP_VALUE_MAX]; 146 struct property_list_callback_data *data = cookie; 147 148 __system_property_read(pi, name, value); 149 data->propfn(name, value, data->cookie); 150 } 151 152 int 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); 158 } 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 174 static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT; 175 static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER; 176 static int gPropFd = -1; 177 178 /* 179 * Connect to the properties server. 180 * 181 * Returns the socket descriptor on success. 182 */ 183 static 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) { 192 ALOGW("UNIX domain socket create failed (errno=%d)\n", errno); 193 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 203 //ALOGW("AF_UNIX connect failed for '%s': %s\n", 204 // fileName, strerror(errno)); 205 close(sock); 206 return -1; 207 } 208 209 return sock; 210 } 211 212 /* 213 * Perform one-time initialization. 214 */ 215 static void init(void) 216 { 217 assert(gPropFd == -1); 218 219 gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME); 220 if (gPropFd < 0) { 221 //ALOGW("not connected to system property server\n"); 222 } else { 223 //ALOGV("Connected to system property server\n"); 224 } 225 } 226 227 int 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 233 //ALOGV("PROPERTY GET [%s]\n", key); 234 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 { 282 ALOGE("Got strange response to property_get request (%d)\n", 283 recvBuf[0]); 284 assert(0); 285 return -1; 286 } 287 //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n", 288 // recvBuf[0], default_value, len, key, value); 289 290 return len; 291 } 292 293 294 int 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 300 //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value); 301 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 331 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 332 void *cookie) 333 { 334 //ALOGV("PROPERTY LIST\n"); 335 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 348 static mutex_t env_lock = MUTEX_INITIALIZER; 349 350 int 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 384 int 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 414 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 415 void *cookie) 416 { 417 return 0; 418 } 419 420 #endif 421