Home | History | Annotate | Download | only in android
      1 /* Copyright (C) 2009 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 #include "android/boot-properties.h"
     14 #include "android/utils/debug.h"
     15 #include "android/utils/system.h"
     16 #include "android/hw-qemud.h"
     17 #include "android/globals.h"
     18 
     19 #define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
     20 
     21 /* define T_ACTIVE to 1 to debug transport communications */
     22 #define  T_ACTIVE  0
     23 
     24 #if T_ACTIVE
     25 #define  T(...)  VERBOSE_PRINT(init,__VA_ARGS__)
     26 #else
     27 #define  T(...)   ((void)0)
     28 #endif
     29 
     30 /* this code supports the list of system properties that will
     31  * be set on boot in the emulated system.
     32  */
     33 
     34 typedef struct BootProperty {
     35     struct BootProperty*  next;
     36     char*                 property;
     37     int                   length;
     38 } BootProperty;
     39 
     40 static BootProperty*
     41 boot_property_alloc( const char*  name,  int  namelen,
     42                      const char*  value, int  valuelen )
     43 {
     44     int            length = namelen + 1 + valuelen;
     45     BootProperty*  prop = android_alloc( sizeof(*prop) + length + 1 );
     46     char*          p;
     47 
     48     prop->next     = NULL;
     49     prop->property = p = (char*)(prop + 1);
     50     prop->length   = length;
     51 
     52     memcpy( p, name, namelen );
     53     p += namelen;
     54     *p++ = '=';
     55     memcpy( p, value, valuelen );
     56     p += valuelen;
     57     *p = '\0';
     58 
     59     return prop;
     60 }
     61 
     62 static BootProperty*   _boot_properties;
     63 static BootProperty**  _boot_properties_tail = &_boot_properties;
     64 static int             _inited;
     65 
     66 int
     67 boot_property_add2( const char*  name, int  namelen,
     68                     const char*  value, int  valuelen )
     69 {
     70     BootProperty*  prop;
     71 
     72     /* check the lengths
     73      */
     74     if (namelen > PROPERTY_MAX_NAME)
     75         return -1;
     76 
     77     if (valuelen > PROPERTY_MAX_VALUE)
     78         return -2;
     79 
     80     /* check that there are not invalid characters in the
     81      * property name
     82      */
     83     const char*  reject = " =$*?'\"";
     84     int          nn;
     85 
     86     for (nn = 0; nn < namelen; nn++) {
     87         if (strchr(reject, name[nn]) != NULL)
     88             return -3;
     89     }
     90 
     91     /* init service if needed */
     92     if (!_inited) {
     93         boot_property_init_service();
     94         _inited = 1;
     95     }
     96 
     97     D("Adding boot property: '%.*s' = '%.*s'",
     98       namelen, name, valuelen, value);
     99 
    100     /* add to the internal list */
    101     prop = boot_property_alloc(name, namelen, value, valuelen);
    102 
    103     *_boot_properties_tail = prop;
    104     _boot_properties_tail  = &prop->next;
    105 
    106     return 0;
    107 }
    108 
    109 
    110 int
    111 boot_property_add( const char*  name, const char*  value )
    112 {
    113     int  namelen = strlen(name);
    114     int  valuelen = strlen(value);
    115 
    116     return boot_property_add2(name, namelen, value, valuelen);
    117 }
    118 
    119 
    120 
    121 #define SERVICE_NAME  "boot-properties"
    122 
    123 static void
    124 boot_property_client_recv( void*         opaque,
    125                            uint8_t*      msg,
    126                            int           msglen,
    127                            QemudClient*  client )
    128 {
    129     /* the 'list' command shall send all boot properties
    130      * to the client, then close the connection.
    131      */
    132     if (msglen == 4 && !memcmp(msg, "list", 4)) {
    133         BootProperty*  prop;
    134         for (prop = _boot_properties; prop != NULL; prop = prop->next) {
    135             qemud_client_send(client, (uint8_t*)prop->property, prop->length);
    136         }
    137 
    138         /* Send a NUL to signal the end of the list. */
    139         qemud_client_send(client, (uint8_t*)"", 1);
    140 
    141         qemud_client_close(client);
    142         return;
    143     }
    144 
    145     /* unknown command ? */
    146     D("%s: ignoring unknown command: %.*s", __FUNCTION__, msglen, msg);
    147 }
    148 
    149 static QemudClient*
    150 boot_property_service_connect( void*          opaque,
    151                                QemudService*  serv,
    152                                int            channel )
    153 {
    154     QemudClient*  client;
    155 
    156     client = qemud_client_new( serv, channel, NULL,
    157                                boot_property_client_recv,
    158                                NULL );
    159 
    160     qemud_client_set_framing(client, 1);
    161     return client;
    162 }
    163 
    164 
    165 void
    166 boot_property_init_service( void )
    167 {
    168     if (!_inited) {
    169         QemudService*  serv = qemud_service_register( SERVICE_NAME,
    170                                                     1, NULL,
    171                                                     boot_property_service_connect );
    172         if (serv == NULL) {
    173             derror("could not register '%s' service", SERVICE_NAME);
    174             return;
    175         }
    176         D("registered '%s' qemud service", SERVICE_NAME);
    177     }
    178 }
    179 
    180 
    181 
    182 void
    183 boot_property_parse_option( const char*  param )
    184 {
    185     char* q = strchr(param,'=');
    186     const char* name;
    187     const char* value;
    188     int   namelen, valuelen, ret;
    189 
    190     if (q == NULL) {
    191         dwarning("boot property missing (=) separator: %s", param);
    192         return;
    193     }
    194 
    195     name    = param;
    196     namelen = q - param;
    197 
    198     value    = q+1;
    199     valuelen = strlen(name) - (namelen+1);
    200 
    201     ret = boot_property_add2(name, namelen, value, valuelen);
    202     if (ret < 0) {
    203         switch (ret) {
    204         case -1:
    205             dwarning("boot property name too long: '%.*s'",
    206                         namelen, name);
    207             break;
    208         case -2:
    209             dwarning("boot property value too long: '%.*s'",
    210                         valuelen, value);
    211             break;
    212         case -3:
    213             dwarning("boot property name contains invalid chars: %.*s",
    214                         namelen, name);
    215             break;
    216         }
    217     }
    218 }
    219