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