• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
property_set(const char * key,const char * value)34 int property_set(const char *key, const char *value)
35 {
36     return __system_property_set(key, value);
37 }
38 
property_get(const char * key,char * value,const char * default_value)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 
property_list_callback(const prop_info * pi,void * cookie)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 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)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  */
connectToServer(const char * fileName)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  */
init(void)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 
property_get(const char * key,char * value,const char * default_value)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 
property_set(const char * key,const char * value)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 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)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 
property_get(const char * key,char * value,const char * default_value)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 
property_set(const char * key,const char * value)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 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)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