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