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