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