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*
boot_property_alloc(const char * name,int namelen,const char * value,int valuelen)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
boot_property_add2(const char * name,int namelen,const char * value,int valuelen)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
boot_property_add(const char * name,const char * value)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
boot_property_client_recv(void * opaque,uint8_t * msg,int msglen,QemudClient * client)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*
boot_property_service_connect(void * opaque,QemudService * serv,int channel)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
boot_property_init_service(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
boot_property_parse_option(const char * param)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