/* Copyright (C) 2009 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "android/boot-properties.h" #include "android/utils/debug.h" #include "android/utils/system.h" #include "android/hw-qemud.h" #include "android/globals.h" #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) /* define T_ACTIVE to 1 to debug transport communications */ #define T_ACTIVE 0 #if T_ACTIVE #define T(...) VERBOSE_PRINT(init,__VA_ARGS__) #else #define T(...) ((void)0) #endif /* this code supports the list of system properties that will * be set on boot in the emulated system. */ typedef struct BootProperty { struct BootProperty* next; char* property; int length; } BootProperty; static BootProperty* boot_property_alloc( const char* name, int namelen, const char* value, int valuelen ) { int length = namelen + 1 + valuelen; BootProperty* prop = android_alloc( sizeof(*prop) + length + 1 ); char* p; prop->next = NULL; prop->property = p = (char*)(prop + 1); prop->length = length; memcpy( p, name, namelen ); p += namelen; *p++ = '='; memcpy( p, value, valuelen ); p += valuelen; *p = '\0'; return prop; } static BootProperty* _boot_properties; static BootProperty** _boot_properties_tail = &_boot_properties; static int _inited; int boot_property_add2( const char* name, int namelen, const char* value, int valuelen ) { BootProperty* prop; /* check the lengths */ if (namelen > PROPERTY_MAX_NAME) return -1; if (valuelen > PROPERTY_MAX_VALUE) return -2; /* check that there are not invalid characters in the * property name */ const char* reject = " =$*?'\""; int nn; for (nn = 0; nn < namelen; nn++) { if (strchr(reject, name[nn]) != NULL) return -3; } /* init service if needed */ if (!_inited) { boot_property_init_service(); _inited = 1; } D("Adding boot property: '%.*s' = '%.*s'", namelen, name, valuelen, value); /* add to the internal list */ prop = boot_property_alloc(name, namelen, value, valuelen); *_boot_properties_tail = prop; _boot_properties_tail = &prop->next; return 0; } int boot_property_add( const char* name, const char* value ) { int namelen = strlen(name); int valuelen = strlen(value); return boot_property_add2(name, namelen, value, valuelen); } #define SERVICE_NAME "boot-properties" static void boot_property_client_recv( void* opaque, uint8_t* msg, int msglen, QemudClient* client ) { /* the 'list' command shall send all boot properties * to the client, then close the connection. */ if (msglen == 4 && !memcmp(msg, "list", 4)) { BootProperty* prop; for (prop = _boot_properties; prop != NULL; prop = prop->next) { qemud_client_send(client, (uint8_t*)prop->property, prop->length); } /* Send a NUL to signal the end of the list. */ qemud_client_send(client, (uint8_t*)"", 1); qemud_client_close(client); return; } /* unknown command ? */ D("%s: ignoring unknown command: %.*s", __FUNCTION__, msglen, msg); } static QemudClient* boot_property_service_connect( void* opaque, QemudService* serv, int channel ) { QemudClient* client; client = qemud_client_new( serv, channel, NULL, boot_property_client_recv, NULL ); qemud_client_set_framing(client, 1); return client; } void boot_property_init_service( void ) { if (!_inited) { QemudService* serv = qemud_service_register( SERVICE_NAME, 1, NULL, boot_property_service_connect ); if (serv == NULL) { derror("could not register '%s' service", SERVICE_NAME); return; } D("registered '%s' qemud service", SERVICE_NAME); } } void boot_property_parse_option( const char* param ) { char* q = strchr(param,'='); const char* name; const char* value; int namelen, valuelen, ret; if (q == NULL) { dwarning("boot property missing (=) separator: %s", param); return; } name = param; namelen = q - param; value = q+1; valuelen = strlen(name) - (namelen+1); ret = boot_property_add2(name, namelen, value, valuelen); if (ret < 0) { switch (ret) { case -1: dwarning("boot property name too long: '%.*s'", namelen, name); break; case -2: dwarning("boot property value too long: '%.*s'", valuelen, value); break; case -3: dwarning("boot property name contains invalid chars: %.*s", namelen, name); break; } } }