blob: 547cc6dc5a847f1db06981278e0771f5753ad59e [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"
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
34static 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
59int 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
77int 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
93int 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
122static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
123static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
124static int gPropFd = -1;
125
126/*
127 * Connect to the properties server.
128 *
129 * Returns the socket descriptor on success.
130 */
131static 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 */
163static 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
175int 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
242int 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
279int 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
296static mutex_t env_lock = MUTEX_INITIALIZER;
297
298int 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
332int 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
362int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
363 void *cookie)
364{
365 return 0;
366}
367
368#endif