aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android/boot-properties.c196
1 files changed, 177 insertions, 19 deletions
diff --git a/android/boot-properties.c b/android/boot-properties.c
index c094202..1a86010 100644
--- a/android/boot-properties.c
+++ b/android/boot-properties.c
@@ -16,6 +16,8 @@
#include "android/hw-qemud.h"
#include "android/globals.h"
+#include "hw/hw.h"
+
#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
/* define T_ACTIVE to 1 to debug transport communications */
@@ -59,10 +61,32 @@ boot_property_alloc( const char* name, int namelen,
return prop;
}
-static BootProperty* _boot_properties;
+static BootProperty* _boot_properties = NULL;
+/* address to store pointer to next new list element */
static BootProperty** _boot_properties_tail = &_boot_properties;
static int _inited;
+/* Clears all existing boot properties
+ */
+static void
+boot_property_clear_all()
+{
+ /* free all elements of the linked list */
+ BootProperty *p = _boot_properties;
+ BootProperty *next = NULL;
+ while (p) {
+ next = p->next;
+ AFREE(p);
+ p = next;
+ }
+
+ /* reset list administration to initial state */
+ _boot_properties = NULL;
+ _boot_properties_tail = &_boot_properties;
+}
+
+/* Appends a new boot property to the end of the internal list.
+ */
int
boot_property_add2( const char* name, int namelen,
const char* value, int valuelen )
@@ -97,7 +121,7 @@ boot_property_add2( const char* name, int namelen,
D("Adding boot property: '%.*s' = '%.*s'",
namelen, name, valuelen, value);
- /* add to the internal list */
+ /* add to the end of the internal list */
prop = boot_property_alloc(name, namelen, value, valuelen);
*_boot_properties_tail = prop;
@@ -106,6 +130,28 @@ boot_property_add2( const char* name, int namelen,
return 0;
}
+/* Prints the warning string corresponding to the error code returned by
+ * boot_propery_add2().
+ */
+static void
+boot_property_raise_warning( int ret, const char* name, int namelen,
+ const char* value, int valuelen )
+{
+ 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;
+ }
+}
int
boot_property_add( const char* name, const char* value )
@@ -116,7 +162,131 @@ boot_property_add( const char* name, const char* value )
return boot_property_add2(name, namelen, value, valuelen);
}
+/* Saves a single BootProperty to file.
+ */
+static int
+boot_property_save_property( QEMUFile *f, BootProperty *p )
+{
+ /* split in key and value, so we can re-use boot_property_add (and its
+ * sanity checks) when loading
+ */
+ char *split = strchr(p->property, '=');
+ if (split == NULL) {
+ D("%s: save failed: illegal key/value pair \"%s\" (missing '=')\n",
+ __FUNCTION__, p->property);
+ qemu_file_set_error(f);
+ return -1;
+ }
+
+ *split = '\0'; /* p->property is now "<key>\0<value>\0" */
+
+ uint32_t key_buf_len = (split - p->property) + 1; // +1: '\0' terminator
+ qemu_put_be32(f, key_buf_len);
+ qemu_put_buffer(f, (uint8_t*) p->property, key_buf_len);
+
+ uint32_t value_buf_len = p->length - key_buf_len + 1; // +1: '\0' terminator
+ qemu_put_be32(f, value_buf_len);
+ qemu_put_buffer(f, (uint8_t*) split + 1, value_buf_len);
+
+ *split = '='; /* restore property to "<key>=<value>\0" */
+
+ return 0;
+}
+
+/* Loads a single boot property from a snapshot file
+ */
+static int
+boot_property_load_property( QEMUFile *f )
+{
+ int ret;
+
+ /* load key */
+ uint32_t key_buf_len = qemu_get_be32(f);
+ char* key = android_alloc(key_buf_len);
+ if ((ret = qemu_get_buffer(f, (uint8_t*)key, key_buf_len) != key_buf_len)) {
+ D("%s: key load failed: expected %d bytes, got %d\n",
+ __FUNCTION__, key_buf_len, ret);
+ goto fail_key;
+ }
+
+ /* load value */
+ uint32_t value_buf_len = qemu_get_be32(f);
+ char* value = android_alloc(value_buf_len);
+ if ((ret = qemu_get_buffer(f, (uint8_t*)value, value_buf_len) != value_buf_len)) {
+ D("%s: value load failed: expected %d bytes, got %d\n",
+ __FUNCTION__, value_buf_len, ret);
+ goto fail_value;
+ }
+
+ /* add the property */
+ ret = boot_property_add2(key, key_buf_len - 1, value, value_buf_len - 1);
+ if (ret < 0) {
+ D("%s: load failed: cannot add boot property (details follow)\n",
+ __FUNCTION__);
+ boot_property_raise_warning(ret, key, key_buf_len - 1, value, value_buf_len - 1);
+ goto fail_value;
+ }
+
+ return 0;
+
+ /* in case of errors, clean up before return */
+ fail_value:
+ AFREE(value);
+ fail_key:
+ AFREE(key);
+ return -EIO;
+}
+
+/* Saves the number of available boot properties to file
+ */
+static void
+boot_property_save_count( QEMUFile* f, BootProperty* p )
+{
+ uint32_t property_count = 0;
+ for (; p; p = p->next) {
+ property_count++;
+ }
+
+ qemu_put_be32(f, property_count);
+}
+
+/* Saves all available boot properties to snapshot.
+ */
+static void
+boot_property_save( QEMUFile* f, QemudService* service, void* opaque )
+{
+ boot_property_save_count(f, _boot_properties);
+
+ BootProperty *p = _boot_properties;
+ for ( ; p; p = p->next) {
+ if (boot_property_save_property(f, p)) {
+ break; /* abort on error */
+ }
+ }
+}
+
+/* Replaces the currently available boot properties by those stored
+ * in a snapshot.
+ */
+static int
+boot_property_load( QEMUFile* f, QemudService* service, void* opaque )
+{
+ int ret;
+
+ /* remove properties from old run */
+ boot_property_clear_all();
+
+ /* load properties from snapshot */
+ uint32_t i, property_count = qemu_get_be32(f);
+ for (i = 0; i < property_count; i++) {
+ if ((ret = boot_property_load_property(f))) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
#define SERVICE_NAME "boot-properties"
@@ -167,9 +337,10 @@ boot_property_init_service( void )
{
if (!_inited) {
QemudService* serv = qemud_service_register( SERVICE_NAME,
- 1, NULL,
- boot_property_service_connect,
- NULL, NULL);
+ 1, NULL,
+ boot_property_service_connect,
+ boot_property_save,
+ boot_property_load);
if (serv == NULL) {
derror("could not register '%s' service", SERVICE_NAME);
return;
@@ -201,19 +372,6 @@ boot_property_parse_option( const char* param )
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;
- }
+ boot_property_raise_warning(ret, name, namelen, value, valuelen);
}
}