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