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 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 #include <cutils/sockets.h> 23 #include <errno.h> 24 #include <assert.h> 25 26 #include <cutils/properties.h> 27 #include "loghack.h" 28 29 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES 30 31 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 32 #include <sys/_system_properties.h> 33 34 int property_set(const char *key, const char *value) 35 { 36 return __system_property_set(key, value); 37 } 38 39 int property_get(const char *key, char *value, const char *default_value) 40 { 41 int len; 42 43 len = __system_property_get(key, value); 44 if(len > 0) { 45 return len; 46 } 47 48 if(default_value) { 49 len = strlen(default_value); 50 memcpy(value, default_value, len + 1); 51 } 52 return len; 53 } 54 55 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 56 void *cookie) 57 { 58 char name[PROP_NAME_MAX]; 59 char value[PROP_VALUE_MAX]; 60 const prop_info *pi; 61 unsigned n; 62 63 for(n = 0; (pi = __system_property_find_nth(n)); n++) { 64 __system_property_read(pi, name, value); 65 propfn(name, value, cookie); 66 } 67 return 0; 68 } 69 70 #elif defined(HAVE_SYSTEM_PROPERTY_SERVER) 71 72 /* 73 * The Linux simulator provides a "system property server" that uses IPC 74 * to set/get/list properties. The file descriptor is shared by all 75 * threads in the process, so we use a mutex to ensure that requests 76 * from multiple threads don't get interleaved. 77 */ 78 #include <stdio.h> 79 #include <sys/types.h> 80 #include <sys/socket.h> 81 #include <sys/un.h> 82 #include <pthread.h> 83 84 static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT; 85 static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER; 86 static int gPropFd = -1; 87 88 /* 89 * Connect to the properties server. 90 * 91 * Returns the socket descriptor on success. 92 */ 93 static int connectToServer(const char* fileName) 94 { 95 int sock = -1; 96 int cc; 97 98 struct sockaddr_un addr; 99 100 sock = socket(AF_UNIX, SOCK_STREAM, 0); 101 if (sock < 0) { 102 LOGW("UNIX domain socket create failed (errno=%d)\n", errno); 103 return -1; 104 } 105 106 /* connect to socket; fails if file doesn't exist */ 107 strcpy(addr.sun_path, fileName); // max 108 bytes 108 addr.sun_family = AF_UNIX; 109 cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr)); 110 if (cc < 0) { 111 // ENOENT means socket file doesn't exist 112 // ECONNREFUSED means socket exists but nobody is listening 113 //LOGW("AF_UNIX connect failed for '%s': %s\n", 114 // fileName, strerror(errno)); 115 close(sock); 116 return -1; 117 } 118 119 return sock; 120 } 121 122 /* 123 * Perform one-time initialization. 124 */ 125 static void init(void) 126 { 127 assert(gPropFd == -1); 128 129 gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME); 130 if (gPropFd < 0) { 131 //LOGW("not connected to system property server\n"); 132 } else { 133 //LOGV("Connected to system property server\n"); 134 } 135 } 136 137 int property_get(const char *key, char *value, const char *default_value) 138 { 139 char sendBuf[1+PROPERTY_KEY_MAX]; 140 char recvBuf[1+PROPERTY_VALUE_MAX]; 141 int len = -1; 142 143 //LOGV("PROPERTY GET [%s]\n", key); 144 145 pthread_once(&gInitOnce, init); 146 if (gPropFd < 0) { 147 /* this mimics the behavior of the device implementation */ 148 if (default_value != NULL) { 149 strcpy(value, default_value); 150 len = strlen(value); 151 } 152 return len; 153 } 154 155 if (strlen(key) >= PROPERTY_KEY_MAX) return -1; 156 157 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind 158 159 sendBuf[0] = (char) kSystemPropertyGet; 160 strcpy(sendBuf+1, key); 161 162 pthread_mutex_lock(&gPropertyFdLock); 163 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) { 164 pthread_mutex_unlock(&gPropertyFdLock); 165 return -1; 166 } 167 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) { 168 pthread_mutex_unlock(&gPropertyFdLock); 169 return -1; 170 } 171 pthread_mutex_unlock(&gPropertyFdLock); 172 173 /* first byte is 0 if value not defined, 1 if found */ 174 if (recvBuf[0] == 0) { 175 if (default_value != NULL) { 176 strcpy(value, default_value); 177 len = strlen(value); 178 } else { 179 /* 180 * If the value isn't defined, hand back an empty string and 181 * a zero length, rather than a failure. This seems wrong, 182 * since you can't tell the difference between "undefined" and 183 * "defined but empty", but it's what the device does. 184 */ 185 value[0] = '\0'; 186 len = 0; 187 } 188 } else if (recvBuf[0] == 1) { 189 strcpy(value, recvBuf+1); 190 len = strlen(value); 191 } else { 192 LOGE("Got strange response to property_get request (%d)\n", 193 recvBuf[0]); 194 assert(0); 195 return -1; 196 } 197 //LOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n", 198 // recvBuf[0], default_value, len, key, value); 199 200 return len; 201 } 202 203 204 int property_set(const char *key, const char *value) 205 { 206 char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX]; 207 char recvBuf[1]; 208 int result = -1; 209 210 //LOGV("PROPERTY SET [%s]: [%s]\n", key, value); 211 212 pthread_once(&gInitOnce, init); 213 if (gPropFd < 0) 214 return -1; 215 216 if (strlen(key) >= PROPERTY_KEY_MAX) return -1; 217 if (strlen(value) >= PROPERTY_VALUE_MAX) return -1; 218 219 memset(sendBuf, 0xdd, sizeof(sendBuf)); // placate valgrind 220 221 sendBuf[0] = (char) kSystemPropertySet; 222 strcpy(sendBuf+1, key); 223 strcpy(sendBuf+1+PROPERTY_KEY_MAX, value); 224 225 pthread_mutex_lock(&gPropertyFdLock); 226 if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) { 227 pthread_mutex_unlock(&gPropertyFdLock); 228 return -1; 229 } 230 if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) { 231 pthread_mutex_unlock(&gPropertyFdLock); 232 return -1; 233 } 234 pthread_mutex_unlock(&gPropertyFdLock); 235 236 if (recvBuf[0] != 1) 237 return -1; 238 return 0; 239 } 240 241 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 242 void *cookie) 243 { 244 //LOGV("PROPERTY LIST\n"); 245 pthread_once(&gInitOnce, init); 246 if (gPropFd < 0) 247 return -1; 248 249 return 0; 250 } 251 252 #else 253 254 /* SUPER-cheesy place-holder implementation for Win32 */ 255 256 #include <cutils/threads.h> 257 258 static mutex_t env_lock = MUTEX_INITIALIZER; 259 260 int property_get(const char *key, char *value, const char *default_value) 261 { 262 char ename[PROPERTY_KEY_MAX + 6]; 263 char *p; 264 int len; 265 266 len = strlen(key); 267 if(len >= PROPERTY_KEY_MAX) return -1; 268 memcpy(ename, "PROP_", 5); 269 memcpy(ename + 5, key, len + 1); 270 271 mutex_lock(&env_lock); 272 273 p = getenv(ename); 274 if(p == 0) p = ""; 275 len = strlen(p); 276 if(len >= PROPERTY_VALUE_MAX) { 277 len = PROPERTY_VALUE_MAX - 1; 278 } 279 280 if((len == 0) && default_value) { 281 len = strlen(default_value); 282 memcpy(value, default_value, len + 1); 283 } else { 284 memcpy(value, p, len); 285 value[len] = 0; 286 } 287 288 mutex_unlock(&env_lock); 289 290 return len; 291 } 292 293 294 int property_set(const char *key, const char *value) 295 { 296 char ename[PROPERTY_KEY_MAX + 6]; 297 char *p; 298 int len; 299 int r; 300 301 if(strlen(value) >= PROPERTY_VALUE_MAX) return -1; 302 303 len = strlen(key); 304 if(len >= PROPERTY_KEY_MAX) return -1; 305 memcpy(ename, "PROP_", 5); 306 memcpy(ename + 5, key, len + 1); 307 308 mutex_lock(&env_lock); 309 #ifdef HAVE_MS_C_RUNTIME 310 { 311 char temp[256]; 312 snprintf( temp, sizeof(temp), "%s=%s", ename, value); 313 putenv(temp); 314 r = 0; 315 } 316 #else 317 r = setenv(ename, value, 1); 318 #endif 319 mutex_unlock(&env_lock); 320 321 return r; 322 } 323 324 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 325 void *cookie) 326 { 327 return 0; 328 } 329 330 #endif 331