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 struct property_list_callback_data
     56 {
     57     void (*propfn)(const char *key, const char *value, void *cookie);
     58     void *cookie;
     59 };
     60 
     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 
     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  */
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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