1318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner/* Copyright (C) 2009 The Android Open Source Project
2318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner**
3318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** This software is licensed under the terms of the GNU General Public
4318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** License version 2, as published by the Free Software Foundation, and
5318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** may be copied, distributed, and modified under those terms.
6318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner**
7318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** This program is distributed in the hope that it will be useful,
8318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** but WITHOUT ANY WARRANTY; without even the implied warranty of
9318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner** GNU General Public License for more details.
11318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner*/
12318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
13318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#include "android/boot-properties.h"
14318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#include "android/utils/debug.h"
15318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#include "android/utils/system.h"
16318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#include "android/hw-qemud.h"
17318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#include "android/globals.h"
18318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
1945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije#include "hw/hw.h"
2045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
21318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
22318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
23318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner/* define T_ACTIVE to 1 to debug transport communications */
24318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#define  T_ACTIVE  0
25318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
26318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#if T_ACTIVE
27318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#define  T(...)  VERBOSE_PRINT(init,__VA_ARGS__)
28318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#else
29318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#define  T(...)   ((void)0)
30318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#endif
31318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
32d68b48725d720a06b24932b170f528929856f3dbDavid 'Digit' Turner/* this code supports the list of system properties that will
33d68b48725d720a06b24932b170f528929856f3dbDavid 'Digit' Turner * be set on boot in the emulated system.
34d68b48725d720a06b24932b170f528929856f3dbDavid 'Digit' Turner */
35d68b48725d720a06b24932b170f528929856f3dbDavid 'Digit' Turner
36318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnertypedef struct BootProperty {
37318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    struct BootProperty*  next;
38318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    char*                 property;
39318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int                   length;
40318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner} BootProperty;
41318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
42318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerstatic BootProperty*
43318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_alloc( const char*  name,  int  namelen,
44318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                     const char*  value, int  valuelen )
45318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
46318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int            length = namelen + 1 + valuelen;
47318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    BootProperty*  prop = android_alloc( sizeof(*prop) + length + 1 );
48318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    char*          p;
49318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
50318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    prop->next     = NULL;
51318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    prop->property = p = (char*)(prop + 1);
52318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    prop->length   = length;
53318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
54318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    memcpy( p, name, namelen );
55318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    p += namelen;
56318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    *p++ = '=';
57318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    memcpy( p, value, valuelen );
58318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    p += valuelen;
59318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    *p = '\0';
60318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
61318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    return prop;
62318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
63318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
6445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic BootProperty*   _boot_properties = NULL;
6545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* address to store pointer to next new list element */
66318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerstatic BootProperty**  _boot_properties_tail = &_boot_properties;
67318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerstatic int             _inited;
68318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
6945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Clears all existing boot properties
7045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
7145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic void
7245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_clear_all()
7345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
7445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* free all elements of the linked list */
7545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    BootProperty *p = _boot_properties;
7645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    BootProperty *next = NULL;
7745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    while (p) {
7845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        next = p->next;
7945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        AFREE(p);
8045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        p = next;
8145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
8245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
8345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* reset list administration to initial state */
8445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    _boot_properties = NULL;
8545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    _boot_properties_tail = &_boot_properties;
8645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
8745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
8845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Appends a new boot property to the end of the internal list.
8945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
90318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerint
91318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_add2( const char*  name, int  namelen,
92318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                    const char*  value, int  valuelen )
93318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
94318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    BootProperty*  prop;
95318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
96318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    /* check the lengths
97318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner     */
98318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (namelen > PROPERTY_MAX_NAME)
99318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        return -1;
100318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
101318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (valuelen > PROPERTY_MAX_VALUE)
102318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        return -2;
103318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
104318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    /* check that there are not invalid characters in the
105318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner     * property name
106318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner     */
107318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    const char*  reject = " =$*?'\"";
108318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int          nn;
109318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
110318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    for (nn = 0; nn < namelen; nn++) {
111318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        if (strchr(reject, name[nn]) != NULL)
112318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            return -3;
113318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
114318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
115318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    /* init service if needed */
116318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (!_inited) {
117318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        boot_property_init_service();
118318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        _inited = 1;
119318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
120318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
121318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    D("Adding boot property: '%.*s' = '%.*s'",
122318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner      namelen, name, valuelen, value);
123318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
12445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* add to the end of the internal list */
125318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    prop = boot_property_alloc(name, namelen, value, valuelen);
126318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
127318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    *_boot_properties_tail = prop;
128318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    _boot_properties_tail  = &prop->next;
129318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
130318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    return 0;
131318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
132318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
13345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Prints the warning string corresponding to the error code returned by
13445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije * boot_propery_add2().
13545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
13645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic void
13745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_raise_warning( int ret, const char*  name, int  namelen,
13845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                             const char*  value, int  valuelen )
13945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
14045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    switch (ret) {
14145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    case -1:
14245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        dwarning("boot property name too long: '%.*s'",
14345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                    namelen, name);
14445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        break;
14545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    case -2:
14645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        dwarning("boot property value too long: '%.*s'",
14745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                    valuelen, value);
14845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        break;
14945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    case -3:
15045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        dwarning("boot property name contains invalid chars: %.*s",
15145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                    namelen, name);
15245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        break;
15345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
15445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
155318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
156318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerint
157318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_add( const char*  name, const char*  value )
158318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
159318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int  namelen = strlen(name);
160318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int  valuelen = strlen(value);
161318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
162318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    return boot_property_add2(name, namelen, value, valuelen);
163318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
164318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
16545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Saves a single BootProperty to file.
16645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
16745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic int
16845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_save_property( QEMUFile  *f, BootProperty  *p )
16945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
17045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* split in key and value, so we can re-use boot_property_add (and its
17145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije     * sanity checks) when loading
17245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije     */
173318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
17445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    char *split = strchr(p->property, '=');
17545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    if (split == NULL) {
17645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        D("%s: save failed: illegal key/value pair \"%s\" (missing '=')\n",
17745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije          __FUNCTION__, p->property);
17845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        qemu_file_set_error(f);
17945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        return -1;
18045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
18145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
18245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    *split = '\0';  /* p->property is now "<key>\0<value>\0" */
18345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
18445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t key_buf_len = (split - p->property) + 1; // +1: '\0' terminator
18545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    qemu_put_be32(f, key_buf_len);
18645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    qemu_put_buffer(f, (uint8_t*) p->property, key_buf_len);
18745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
18845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t value_buf_len = p->length - key_buf_len + 1; // +1: '\0' terminator
18945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    qemu_put_be32(f, value_buf_len);
19045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    qemu_put_buffer(f, (uint8_t*) split + 1, value_buf_len);
19145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
19245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    *split = '=';  /* restore property to "<key>=<value>\0" */
19345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
19445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    return 0;
19545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
19645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
19745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Loads a single boot property from a snapshot file
19845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
19945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic int
20045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_load_property( QEMUFile  *f )
20145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
20245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    int ret;
20345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
20445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* load key */
20545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t key_buf_len = qemu_get_be32(f);
20645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    char* key = android_alloc(key_buf_len);
20745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    if ((ret = qemu_get_buffer(f, (uint8_t*)key, key_buf_len) != key_buf_len)) {
20845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        D("%s: key load failed: expected %d bytes, got %d\n",
20945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije          __FUNCTION__, key_buf_len, ret);
21045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        goto fail_key;
21145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
21245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
21345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* load value */
21445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t value_buf_len = qemu_get_be32(f);
21545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    char* value = android_alloc(value_buf_len);
21645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    if ((ret = qemu_get_buffer(f, (uint8_t*)value, value_buf_len) != value_buf_len)) {
21745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        D("%s: value load failed: expected %d bytes, got %d\n",
21845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije          __FUNCTION__, value_buf_len, ret);
21945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        goto fail_value;
22045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
22145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
22245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* add the property */
22345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    ret = boot_property_add2(key, key_buf_len - 1, value, value_buf_len - 1);
22445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    if (ret < 0) {
22545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        D("%s: load failed: cannot add boot property (details follow)\n",
22645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije          __FUNCTION__);
22745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        boot_property_raise_warning(ret, key, key_buf_len - 1, value, value_buf_len - 1);
22845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        goto fail_value;
22945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
23045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
23145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    return 0;
23245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
23345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* in case of errors, clean up before return */
23445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    fail_value:
23545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        AFREE(value);
23645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    fail_key:
23745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        AFREE(key);
23845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        return -EIO;
23945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
24045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
24145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Saves the number of available boot properties to file
24245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
24345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic void
24445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_save_count( QEMUFile*  f, BootProperty*  p )
24545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
24645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t property_count = 0;
24745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    for (; p; p = p->next) {
24845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        property_count++;
24945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
25045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
25145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    qemu_put_be32(f, property_count);
25245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
25345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
25445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Saves all available boot properties to snapshot.
25545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
25645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic void
25745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_save( QEMUFile*  f, QemudService*  service, void*  opaque )
25845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
25945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    boot_property_save_count(f, _boot_properties);
26045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
26145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    BootProperty *p = _boot_properties;
26245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    for ( ; p; p = p->next) {
26345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        if (boot_property_save_property(f, p)) {
26445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije            break;  /* abort on error */
26545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        }
26645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
26745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
26845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
26945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije/* Replaces the currently available boot properties by those stored
27045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije * in a snapshot.
27145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije */
27245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijestatic int
27345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thijeboot_property_load( QEMUFile*  f, QemudService*  service, void*  opaque )
27445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije{
27545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    int ret;
27645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
27745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* remove properties from old run */
27845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    boot_property_clear_all();
27945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
28045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    /* load properties from snapshot */
28145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    uint32_t i, property_count = qemu_get_be32(f);
28245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    for (i = 0; i < property_count; i++) {
28345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        if ((ret = boot_property_load_property(f))) {
28445041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije            return ret;
28545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        }
28645041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    }
28745041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije
28845041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije    return 0;
28945041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije}
290318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
291318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner#define SERVICE_NAME  "boot-properties"
292318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
293318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerstatic void
294318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_client_recv( void*         opaque,
295318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                           uint8_t*      msg,
296318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                           int           msglen,
297318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                           QemudClient*  client )
298318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
299318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    /* the 'list' command shall send all boot properties
300318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner     * to the client, then close the connection.
301318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner     */
302318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (msglen == 4 && !memcmp(msg, "list", 4)) {
303318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        BootProperty*  prop;
304318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        for (prop = _boot_properties; prop != NULL; prop = prop->next) {
305318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            qemud_client_send(client, (uint8_t*)prop->property, prop->length);
306318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        }
30738f8467357f731c4ced8548c6bb65e95745c7effDries Harnie
30838f8467357f731c4ced8548c6bb65e95745c7effDries Harnie        /* Send a NUL to signal the end of the list. */
30938f8467357f731c4ced8548c6bb65e95745c7effDries Harnie        qemud_client_send(client, (uint8_t*)"", 1);
31038f8467357f731c4ced8548c6bb65e95745c7effDries Harnie
311318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        return;
312318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
313318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
314318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    /* unknown command ? */
315318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    D("%s: ignoring unknown command: %.*s", __FUNCTION__, msglen, msg);
316318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
317318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
318318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerstatic QemudClient*
319318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_service_connect( void*          opaque,
320318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                               QemudService*  serv,
3214c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                               int            channel,
3224c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                               const char*    client_param )
323318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
324318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    QemudClient*  client;
325318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
3264c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    client = qemud_client_new( serv, channel, client_param, NULL,
327318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                               boot_property_client_recv,
328871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                               NULL, NULL, NULL );
329318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
330318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    qemud_client_set_framing(client, 1);
331318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    return client;
332318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
333318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
334318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
335318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnervoid
336318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_init_service( void )
337318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
338318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (!_inited) {
339318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        QemudService*  serv = qemud_service_register( SERVICE_NAME,
34045041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                                                      1, NULL,
34145041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                                                      boot_property_service_connect,
34245041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                                                      boot_property_save,
34345041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije                                                      boot_property_load);
344318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        if (serv == NULL) {
345318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            derror("could not register '%s' service", SERVICE_NAME);
346318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            return;
347318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        }
348318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        D("registered '%s' qemud service", SERVICE_NAME);
349318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
350318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
351318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
352318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
353318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
354318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnervoid
355318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerboot_property_parse_option( const char*  param )
356318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner{
357318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    char* q = strchr(param,'=');
358318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    const char* name;
359318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    const char* value;
360318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    int   namelen, valuelen, ret;
361318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
362318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (q == NULL) {
363318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        dwarning("boot property missing (=) separator: %s", param);
364318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner        return;
365318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
366318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
367318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    name    = param;
368318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    namelen = q - param;
369318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
370318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    value    = q+1;
371318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    valuelen = strlen(name) - (namelen+1);
372318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner
373318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    ret = boot_property_add2(name, namelen, value, valuelen);
374318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    if (ret < 0) {
37545041e34b979d2ae49b985a1cb98117e71904a16Ot ten Thije        boot_property_raise_warning(ret, name, namelen, value, valuelen);
376318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner    }
377318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner}
378