• 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 // #define LOG_NDEBUG 0
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <unistd.h>
24 #include <cutils/sockets.h>
25 #include <errno.h>
26 #include <assert.h>
27 
28 #include <cutils/properties.h>
29 #include <stdbool.h>
30 #include <inttypes.h>
31 #include "loghack.h"
32 
property_get_bool(const char * key,int8_t default_value)33 int8_t property_get_bool(const char *key, int8_t default_value) {
34     if (!key) {
35         return default_value;
36     }
37 
38     int8_t result = default_value;
39     char buf[PROPERTY_VALUE_MAX] = {'\0',};
40 
41     int len = property_get(key, buf, "");
42     if (len == 1) {
43         char ch = buf[0];
44         if (ch == '0' || ch == 'n') {
45             result = false;
46         } else if (ch == '1' || ch == 'y') {
47             result = true;
48         }
49     } else if (len > 1) {
50          if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
51             result = false;
52         } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
53             result = true;
54         }
55     }
56 
57     return result;
58 }
59 
60 // Convert string property to int (default if fails); return default value if out of bounds
property_get_imax(const char * key,intmax_t lower_bound,intmax_t upper_bound,intmax_t default_value)61 static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
62         intmax_t default_value) {
63     if (!key) {
64         return default_value;
65     }
66 
67     intmax_t result = default_value;
68     char buf[PROPERTY_VALUE_MAX] = {'\0',};
69     char *end = NULL;
70 
71     int len = property_get(key, buf, "");
72     if (len > 0) {
73         int tmp = errno;
74         errno = 0;
75 
76         // Infer base automatically
77         result = strtoimax(buf, &end, /*base*/0);
78         if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
79             // Over or underflow
80             result = default_value;
81             ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
82         } else if (result < lower_bound || result > upper_bound) {
83             // Out of range of requested bounds
84             result = default_value;
85             ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
86         } else if (end == buf) {
87             // Numeric conversion failed
88             result = default_value;
89             ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
90                     __FUNCTION__, key, default_value);
91         }
92 
93         errno = tmp;
94     }
95 
96     return result;
97 }
98 
property_get_int64(const char * key,int64_t default_value)99 int64_t property_get_int64(const char *key, int64_t default_value) {
100     return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
101 }
102 
property_get_int32(const char * key,int32_t default_value)103 int32_t property_get_int32(const char *key, int32_t default_value) {
104     return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
105 }
106 
107 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
108 
109 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
110 #include <sys/_system_properties.h>
111 
property_set(const char * key,const char * value)112 int property_set(const char *key, const char *value)
113 {
114     return __system_property_set(key, value);
115 }
116 
property_get(const char * key,char * value,const char * default_value)117 int property_get(const char *key, char *value, const char *default_value)
118 {
119     int len;
120 
121     len = __system_property_get(key, value);
122     if(len > 0) {
123         return len;
124     }
125     if(default_value) {
126         len = strlen(default_value);
127         if (len >= PROPERTY_VALUE_MAX) {
128             len = PROPERTY_VALUE_MAX - 1;
129         }
130         memcpy(value, default_value, len);
131         value[len] = '\0';
132     }
133     return len;
134 }
135 
136 struct property_list_callback_data
137 {
138     void (*propfn)(const char *key, const char *value, void *cookie);
139     void *cookie;
140 };
141 
property_list_callback(const prop_info * pi,void * cookie)142 static void property_list_callback(const prop_info *pi, void *cookie)
143 {
144     char name[PROP_NAME_MAX];
145     char value[PROP_VALUE_MAX];
146     struct property_list_callback_data *data = cookie;
147 
148     __system_property_read(pi, name, value);
149     data->propfn(name, value, data->cookie);
150 }
151 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)152 int property_list(
153         void (*propfn)(const char *key, const char *value, void *cookie),
154         void *cookie)
155 {
156     struct property_list_callback_data data = { propfn, cookie };
157     return __system_property_foreach(property_list_callback, &data);
158 }
159 
160 #elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
161 
162 /*
163  * The Linux simulator provides a "system property server" that uses IPC
164  * to set/get/list properties.  The file descriptor is shared by all
165  * threads in the process, so we use a mutex to ensure that requests
166  * from multiple threads don't get interleaved.
167  */
168 #include <stdio.h>
169 #include <sys/types.h>
170 #include <sys/socket.h>
171 #include <sys/un.h>
172 #include <pthread.h>
173 
174 static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
175 static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
176 static int gPropFd = -1;
177 
178 /*
179  * Connect to the properties server.
180  *
181  * Returns the socket descriptor on success.
182  */
connectToServer(const char * fileName)183 static int connectToServer(const char* fileName)
184 {
185     int sock = -1;
186     int cc;
187 
188     struct sockaddr_un addr;
189 
190     sock = socket(AF_UNIX, SOCK_STREAM, 0);
191     if (sock < 0) {
192         ALOGW("UNIX domain socket create failed (errno=%d)\n", errno);
193         return -1;
194     }
195 
196     /* connect to socket; fails if file doesn't exist */
197     strcpy(addr.sun_path, fileName);    // max 108 bytes
198     addr.sun_family = AF_UNIX;
199     cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
200     if (cc < 0) {
201         // ENOENT means socket file doesn't exist
202         // ECONNREFUSED means socket exists but nobody is listening
203         //ALOGW("AF_UNIX connect failed for '%s': %s\n",
204         //    fileName, strerror(errno));
205         close(sock);
206         return -1;
207     }
208 
209     return sock;
210 }
211 
212 /*
213  * Perform one-time initialization.
214  */
init(void)215 static void init(void)
216 {
217     assert(gPropFd == -1);
218 
219     gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
220     if (gPropFd < 0) {
221         //ALOGW("not connected to system property server\n");
222     } else {
223         //ALOGV("Connected to system property server\n");
224     }
225 }
226 
property_get(const char * key,char * value,const char * default_value)227 int property_get(const char *key, char *value, const char *default_value)
228 {
229     char sendBuf[1+PROPERTY_KEY_MAX];
230     char recvBuf[1+PROPERTY_VALUE_MAX];
231     int len = -1;
232 
233     //ALOGV("PROPERTY GET [%s]\n", key);
234 
235     pthread_once(&gInitOnce, init);
236     if (gPropFd < 0) {
237         /* this mimics the behavior of the device implementation */
238         if (default_value != NULL) {
239             strcpy(value, default_value);
240             len = strlen(value);
241         }
242         return len;
243     }
244 
245     if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
246 
247     memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
248 
249     sendBuf[0] = (char) kSystemPropertyGet;
250     strcpy(sendBuf+1, key);
251 
252     pthread_mutex_lock(&gPropertyFdLock);
253     if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
254         pthread_mutex_unlock(&gPropertyFdLock);
255         return -1;
256     }
257     if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
258         pthread_mutex_unlock(&gPropertyFdLock);
259         return -1;
260     }
261     pthread_mutex_unlock(&gPropertyFdLock);
262 
263     /* first byte is 0 if value not defined, 1 if found */
264     if (recvBuf[0] == 0) {
265         if (default_value != NULL) {
266             strcpy(value, default_value);
267             len = strlen(value);
268         } else {
269             /*
270              * If the value isn't defined, hand back an empty string and
271              * a zero length, rather than a failure.  This seems wrong,
272              * since you can't tell the difference between "undefined" and
273              * "defined but empty", but it's what the device does.
274              */
275             value[0] = '\0';
276             len = 0;
277         }
278     } else if (recvBuf[0] == 1) {
279         strcpy(value, recvBuf+1);
280         len = strlen(value);
281     } else {
282         ALOGE("Got strange response to property_get request (%d)\n",
283             recvBuf[0]);
284         assert(0);
285         return -1;
286     }
287     //ALOGV("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
288     //    recvBuf[0], default_value, len, key, value);
289 
290     return len;
291 }
292 
293 
property_set(const char * key,const char * value)294 int property_set(const char *key, const char *value)
295 {
296     char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
297     char recvBuf[1];
298     int result = -1;
299 
300     //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);
301 
302     pthread_once(&gInitOnce, init);
303     if (gPropFd < 0)
304         return -1;
305 
306     if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
307     if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
308 
309     memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
310 
311     sendBuf[0] = (char) kSystemPropertySet;
312     strcpy(sendBuf+1, key);
313     strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
314 
315     pthread_mutex_lock(&gPropertyFdLock);
316     if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
317         pthread_mutex_unlock(&gPropertyFdLock);
318         return -1;
319     }
320     if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
321         pthread_mutex_unlock(&gPropertyFdLock);
322         return -1;
323     }
324     pthread_mutex_unlock(&gPropertyFdLock);
325 
326     if (recvBuf[0] != 1)
327         return -1;
328     return 0;
329 }
330 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)331 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
332                   void *cookie)
333 {
334     //ALOGV("PROPERTY LIST\n");
335     pthread_once(&gInitOnce, init);
336     if (gPropFd < 0)
337         return -1;
338 
339     return 0;
340 }
341 
342 #else
343 
344 /* SUPER-cheesy place-holder implementation for Win32 */
345 
346 #include <cutils/threads.h>
347 
348 static mutex_t  env_lock = MUTEX_INITIALIZER;
349 
property_get(const char * key,char * value,const char * default_value)350 int property_get(const char *key, char *value, const char *default_value)
351 {
352     char ename[PROPERTY_KEY_MAX + 6];
353     char *p;
354     int len;
355 
356     len = strlen(key);
357     if(len >= PROPERTY_KEY_MAX) return -1;
358     memcpy(ename, "PROP_", 5);
359     memcpy(ename + 5, key, len + 1);
360 
361     mutex_lock(&env_lock);
362 
363     p = getenv(ename);
364     if(p == 0) p = "";
365     len = strlen(p);
366     if(len >= PROPERTY_VALUE_MAX) {
367         len = PROPERTY_VALUE_MAX - 1;
368     }
369 
370     if((len == 0) && default_value) {
371         len = strlen(default_value);
372         memcpy(value, default_value, len + 1);
373     } else {
374         memcpy(value, p, len);
375         value[len] = 0;
376     }
377 
378     mutex_unlock(&env_lock);
379 
380     return len;
381 }
382 
383 
property_set(const char * key,const char * value)384 int property_set(const char *key, const char *value)
385 {
386     char ename[PROPERTY_KEY_MAX + 6];
387     char *p;
388     int len;
389     int r;
390 
391     if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
392 
393     len = strlen(key);
394     if(len >= PROPERTY_KEY_MAX) return -1;
395     memcpy(ename, "PROP_", 5);
396     memcpy(ename + 5, key, len + 1);
397 
398     mutex_lock(&env_lock);
399 #ifdef HAVE_MS_C_RUNTIME
400     {
401         char  temp[256];
402         snprintf( temp, sizeof(temp), "%s=%s", ename, value);
403         putenv(temp);
404         r = 0;
405     }
406 #else
407     r = setenv(ename, value, 1);
408 #endif
409     mutex_unlock(&env_lock);
410 
411     return r;
412 }
413 
property_list(void (* propfn)(const char * key,const char * value,void * cookie),void * cookie)414 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
415                   void *cookie)
416 {
417     return 0;
418 }
419 
420 #endif
421