OSDN Git Service

2631c584d720c8e962b58c1b25c1f47ee3cc0c92
[android-x86/hardware-libhardware_legacy.git] / qemu / qemu.c
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* this file contains various functions used by all libhardware modules
18  * that support QEMU emulation
19  */
20 #include "qemu.h"
21 #define  LOG_TAG  "hardware-qemu"
22 #include <cutils/log.h>
23 #include <cutils/properties.h>
24 #include <cutils/sockets.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <termios.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30
31 #define  QEMU_DEBUG  0
32
33 #if QEMU_DEBUG
34 #  define  D(...)   LOGD(__VA_ARGS__)
35 #else
36 #  define  D(...)   ((void)0)
37 #endif
38
39
40 int
41 qemu_check(void)
42 {
43     static int  in_qemu = -1;
44
45     if (__builtin_expect(in_qemu < 0,0)) {
46         char  propBuf[PROPERTY_VALUE_MAX];
47         property_get("ro.kernel.qemu", propBuf, "");
48         in_qemu = (propBuf[0] == '1');
49     }
50     return in_qemu;
51 }
52
53
54 int
55 qemu_channel_open( QemuChannel*  channel,
56                    const char*   name,
57                    int           mode )
58 {
59     int  fd = -1;
60
61     /* initialize the channel is needed */
62     if (!channel->is_inited)
63     {
64         int  done = 0;
65
66         // try to connect to qemud socket first
67         do {
68             snprintf(channel->device, sizeof channel->device,
69                      "qemud_%s", name);
70
71             fd = socket_local_client( channel->device,
72                                       ANDROID_SOCKET_NAMESPACE_RESERVED,
73                                       SOCK_STREAM );
74             if (fd < 0) {
75                 D("no '%s' control socket available: %s",
76                   channel->device, strerror(errno));
77                 break;
78             }
79             close(fd);
80             channel->is_qemud = 1;
81             done = 1;
82         } while (0);
83
84         // otherwise, look for a kernel-provided device name
85         if (!done) do {
86             char   key[PROPERTY_KEY_MAX];
87             char   prop[PROPERTY_VALUE_MAX];
88             int    ret;
89
90             ret = snprintf(key, sizeof key, "ro.kernel.android.%s", name);
91             if (ret >= (int)sizeof key)
92                 break;
93
94             if (property_get(key, prop, "") == 0) {
95                 D("no kernel-provided %s device name", name);
96                 break;
97             }
98
99             ret = snprintf(channel->device, sizeof channel->device,
100                            "/dev/%s", prop);
101             if (ret >= (int)sizeof channel->device) {
102                 D("%s device name too long: '%s'", name, prop);
103                 break;
104             }
105             channel->is_tty = !memcmp("/dev/tty", channel->device, 8);
106             done            = 1;
107
108         } while (0);
109
110         channel->is_available = done; 
111         channel->is_inited    = 1;
112     }
113
114     /* try to open the file */
115     if (!channel->is_available) {
116         fd = -1;
117         errno = ENOENT;
118     } else if (channel->is_qemud) {
119         do {
120             fd = socket_local_client( channel->device,
121                                       ANDROID_SOCKET_NAMESPACE_RESERVED,
122                                       SOCK_STREAM );
123         } while (fd < 0 && errno == EINTR);
124     } else {
125         do {
126             fd = open(channel->device, mode);
127         } while (fd < 0 && errno == EINTR);
128
129         /* disable ECHO on serial lines */
130         if (fd >= 0 && channel->is_tty) {
131             struct termios  ios;
132             tcgetattr( fd, &ios );
133             ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
134             tcsetattr( fd, TCSANOW, &ios );
135         }
136     }
137     return fd;
138 }
139
140
141 static int
142 qemu_command_vformat( char*        buffer, 
143                       int          buffer_size,
144                       const char*  format,
145                       va_list      args )
146 {
147     char     header[5];
148     int      len;
149
150     if (buffer_size < 6)
151         return -1;
152
153     len = vsnprintf(buffer+4, buffer_size-4, format, args);
154     if (len >= buffer_size-4)
155         return -1;
156
157     snprintf(header, sizeof header, "%04x", len);
158     memcpy(buffer, header, 4);
159     return len + 4;
160 }
161
162 extern int
163 qemu_command_format( char*        buffer, 
164                      int          buffer_size,
165                      const char*  format,
166                      ... )
167 {
168     va_list  args;
169     int      ret;
170
171     va_start(args, format);
172     ret = qemu_command_format(buffer, buffer_size, format, args);
173     va_end(args);
174     return ret;
175 }
176
177
178 static int
179 qemu_control_fd(void)
180 {
181     static QemuChannel  channel[1];
182     int                 fd;
183
184     fd = qemu_channel_open( channel, "control", O_RDWR );
185     if (fd < 0) {
186         D("%s: could not open control channel: %s", __FUNCTION__,
187           strerror(errno));
188     }
189     return fd;
190 }
191
192 static int
193 qemu_control_write( int  fd, const char*  cmd, int  len )
194 {
195     int  len2;
196     do {
197         len2 = write(fd, cmd, len);
198     } while (len2 < 0 && errno == EINTR);
199     return len2;
200 }
201
202 static int
203 qemu_control_read( int  fd, char*  buff, int  len )
204 {
205     int  len2;
206     do {
207         len2 = read(fd, buff, len);
208     } while (len2 < 0 && errno == EINTR);
209     return len2;
210 }
211
212 static int
213 qemu_control_send(const char*  cmd, int  len)
214 {
215     int  fd, len2;
216
217     if (len < 0) {
218         errno = EINVAL;
219         return -1;
220     }
221
222     fd = qemu_control_fd();
223     if (fd < 0)
224         return -1;
225
226     len2 = qemu_control_write(fd, cmd, len);
227     close(fd);
228     if (len2 != len) {
229         D("%s: could not send everything %d < %d",
230           __FUNCTION__, len2, len);
231         return -1;
232     }
233     return 0;
234 }
235
236
237 int
238 qemu_control_command( const char*  fmt, ... )
239 {
240     va_list  args;
241     char     command[256];
242     int      len, fd;
243
244     va_start(args, fmt);
245     len = qemu_command_vformat( command, sizeof command, fmt, args );
246     va_end(args);
247
248     if (len < 0 || len >= (int)sizeof command) {
249         if (len < 0) {
250             D("%s: could not send: %s", __FUNCTION__, strerror(errno));
251         } else {
252             D("%s: too large %d > %d", __FUNCTION__, len, (int)(sizeof command));
253         }
254         errno = EINVAL;
255         return -1;
256     }
257
258     return qemu_control_send( command, len );
259 }
260
261 extern int  qemu_control_query( const char*  question, int  questionlen,
262                                 char*        answer,   int  answersize )
263 {
264     int   ret, fd, len, result = -1;
265     char  header[5], *end;
266
267     if (questionlen <= 0) {
268         errno = EINVAL;
269         return -1;
270     }
271
272     fd = qemu_control_fd();
273     if (fd < 0)
274         return -1;
275
276     ret = qemu_control_write( fd, question, questionlen );
277     if (ret != questionlen) {
278         D("%s: could not write all: %d < %d", __FUNCTION__,
279           ret, questionlen);
280         goto Exit;
281     }
282
283     /* read a 4-byte header giving the length of the following content */
284     ret = qemu_control_read( fd, header, 4 );
285     if (ret != 4) {
286         D("%s: could not read header (%d != 4)",
287           __FUNCTION__, ret);
288         goto Exit;
289     }
290
291     header[5] = 0;
292     len = strtol( header, &end,  16 );
293     if ( len < 0 || end == NULL || end != header+4 || len > answersize ) {
294         D("%s: could not parse header: '%s'",
295           __FUNCTION__, header);
296         goto Exit;
297     }
298
299     /* read the answer */
300     ret = qemu_control_read( fd, answer, len );
301     if (ret != len) {
302         D("%s: could not read all of answer %d < %d",
303           __FUNCTION__, ret, len);
304         goto Exit;
305     }
306
307     result = len;
308
309 Exit:
310     close(fd);
311     return result;
312 }