Home | History | Annotate | Download | only in libcutils
      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 
     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
     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 
     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 
    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 
    112 int property_set(const char *key, const char *value)
    113 {
    114     return __system_property_set(key, value);
    115 }
    116 
    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 
    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 
    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  */
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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