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 static int 54 qemu_fd_write( int fd, const char* cmd, int len ) 55 { 56 int len2; 57 do { 58 len2 = write(fd, cmd, len); 59 } while (len2 < 0 && errno == EINTR); 60 return len2; 61 } 62 63 static int 64 qemu_fd_read( int fd, char* buff, int len ) 65 { 66 int len2; 67 do { 68 len2 = read(fd, buff, len); 69 } while (len2 < 0 && errno == EINTR); 70 return len2; 71 } 72 73 74 static int 75 qemu_channel_open_qemud( QemuChannel* channel, 76 const char* name ) 77 { 78 int fd, ret, namelen = strlen(name); 79 char answer[2]; 80 81 fd = socket_local_client( "qemud", 82 ANDROID_SOCKET_NAMESPACE_RESERVED, 83 SOCK_STREAM ); 84 if (fd < 0) { 85 D("no qemud control socket: %s", strerror(errno)); 86 return -1; 87 } 88 89 /* send service name to connect */ 90 if (qemu_fd_write(fd, name, namelen) != namelen) { 91 D("can't send service name to qemud: %s", 92 strerror(errno)); 93 close(fd); 94 return -1; 95 } 96 97 /* read answer from daemon */ 98 if (qemu_fd_read(fd, answer, 2) != 2 || 99 answer[0] != 'O' || answer[1] != 'K') { 100 D("cant' connect to %s service through qemud", name); 101 close(fd); 102 return -1; 103 } 104 105 channel->is_qemud = 1; 106 channel->fd = fd; 107 return 0; 108 } 109 110 111 static int 112 qemu_channel_open_qemud_old( QemuChannel* channel, 113 const char* name ) 114 { 115 int fd; 116 117 snprintf(channel->device, sizeof channel->device, 118 "qemud_%s", name); 119 120 fd = socket_local_client( channel->device, 121 ANDROID_SOCKET_NAMESPACE_RESERVED, 122 SOCK_STREAM ); 123 if (fd < 0) { 124 D("no '%s' control socket available: %s", 125 channel->device, strerror(errno)); 126 return -1; 127 } 128 129 close(fd); 130 channel->is_qemud_old = 1; 131 return 0; 132 } 133 134 135 static int 136 qemu_channel_open_tty( QemuChannel* channel, 137 const char* name, 138 int mode ) 139 { 140 char key[PROPERTY_KEY_MAX]; 141 char prop[PROPERTY_VALUE_MAX]; 142 int ret; 143 144 ret = snprintf(key, sizeof key, "ro.kernel.android.%s", name); 145 if (ret >= (int)sizeof key) 146 return -1; 147 148 if (property_get(key, prop, "") == 0) { 149 D("no kernel-provided %s device name", name); 150 return -1; 151 } 152 153 ret = snprintf(channel->device, sizeof channel->device, 154 "/dev/%s", prop); 155 if (ret >= (int)sizeof channel->device) { 156 D("%s device name too long: '%s'", name, prop); 157 return -1; 158 } 159 160 channel->is_tty = !memcmp("/dev/tty", channel->device, 8); 161 return 0; 162 } 163 164 int 165 qemu_channel_open( QemuChannel* channel, 166 const char* name, 167 int mode ) 168 { 169 int fd = -1; 170 171 /* initialize the channel is needed */ 172 if (!channel->is_inited) 173 { 174 channel->is_inited = 1; 175 176 do { 177 if (qemu_channel_open_qemud(channel, name) == 0) 178 break; 179 180 if (qemu_channel_open_qemud_old(channel, name) == 0) 181 break; 182 183 if (qemu_channel_open_tty(channel, name, mode) == 0) 184 break; 185 186 channel->is_available = 0; 187 return -1; 188 } while (0); 189 190 channel->is_available = 1; 191 } 192 193 /* try to open the file */ 194 if (!channel->is_available) { 195 errno = ENOENT; 196 return -1; 197 } 198 199 if (channel->is_qemud) { 200 return dup(channel->fd); 201 } 202 203 if (channel->is_qemud_old) { 204 do { 205 fd = socket_local_client( channel->device, 206 ANDROID_SOCKET_NAMESPACE_RESERVED, 207 SOCK_STREAM ); 208 } while (fd < 0 && errno == EINTR); 209 } 210 else /* /dev/ttySn ? */ 211 { 212 do { 213 fd = open(channel->device, mode); 214 } while (fd < 0 && errno == EINTR); 215 216 /* disable ECHO on serial lines */ 217 if (fd >= 0 && channel->is_tty) { 218 struct termios ios; 219 tcgetattr( fd, &ios ); 220 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */ 221 tcsetattr( fd, TCSANOW, &ios ); 222 } 223 } 224 return fd; 225 } 226 227 228 static int 229 qemu_command_vformat( char* buffer, 230 int buffer_size, 231 const char* format, 232 va_list args ) 233 { 234 char header[5]; 235 int len; 236 237 if (buffer_size < 6) 238 return -1; 239 240 len = vsnprintf(buffer+4, buffer_size-4, format, args); 241 if (len >= buffer_size-4) 242 return -1; 243 244 snprintf(header, sizeof header, "%04x", len); 245 memcpy(buffer, header, 4); 246 return len + 4; 247 } 248 249 extern int 250 qemu_command_format( char* buffer, 251 int buffer_size, 252 const char* format, 253 ... ) 254 { 255 va_list args; 256 int ret; 257 258 va_start(args, format); 259 ret = qemu_command_format(buffer, buffer_size, format, args); 260 va_end(args); 261 return ret; 262 } 263 264 265 static int 266 qemu_control_fd(void) 267 { 268 static QemuChannel channel[1]; 269 int fd; 270 271 fd = qemu_channel_open( channel, "hw-control", O_RDWR ); 272 if (fd < 0) { 273 D("%s: could not open control channel: %s", __FUNCTION__, 274 strerror(errno)); 275 } 276 return fd; 277 } 278 279 static int 280 qemu_control_send(const char* cmd, int len) 281 { 282 int fd, len2; 283 284 if (len < 0) { 285 errno = EINVAL; 286 return -1; 287 } 288 289 fd = qemu_control_fd(); 290 if (fd < 0) 291 return -1; 292 293 len2 = qemu_fd_write(fd, cmd, len); 294 close(fd); 295 if (len2 != len) { 296 D("%s: could not send everything %d < %d", 297 __FUNCTION__, len2, len); 298 return -1; 299 } 300 return 0; 301 } 302 303 304 int 305 qemu_control_command( const char* fmt, ... ) 306 { 307 va_list args; 308 char command[256]; 309 int len, fd; 310 311 va_start(args, fmt); 312 len = qemu_command_vformat( command, sizeof command, fmt, args ); 313 va_end(args); 314 315 if (len < 0 || len >= (int)sizeof command) { 316 if (len < 0) { 317 D("%s: could not send: %s", __FUNCTION__, strerror(errno)); 318 } else { 319 D("%s: too large %d > %d", __FUNCTION__, len, (int)(sizeof command)); 320 } 321 errno = EINVAL; 322 return -1; 323 } 324 325 return qemu_control_send( command, len ); 326 } 327 328 extern int qemu_control_query( const char* question, int questionlen, 329 char* answer, int answersize ) 330 { 331 int ret, fd, len, result = -1; 332 char header[5], *end; 333 334 if (questionlen <= 0) { 335 errno = EINVAL; 336 return -1; 337 } 338 339 fd = qemu_control_fd(); 340 if (fd < 0) 341 return -1; 342 343 ret = qemu_fd_write( fd, question, questionlen ); 344 if (ret != questionlen) { 345 D("%s: could not write all: %d < %d", __FUNCTION__, 346 ret, questionlen); 347 goto Exit; 348 } 349 350 /* read a 4-byte header giving the length of the following content */ 351 ret = qemu_fd_read( fd, header, 4 ); 352 if (ret != 4) { 353 D("%s: could not read header (%d != 4)", 354 __FUNCTION__, ret); 355 goto Exit; 356 } 357 358 header[4] = 0; 359 len = strtol( header, &end, 16 ); 360 if ( len < 0 || end == NULL || end != header+4 || len > answersize ) { 361 D("%s: could not parse header: '%s'", 362 __FUNCTION__, header); 363 goto Exit; 364 } 365 366 /* read the answer */ 367 ret = qemu_fd_read( fd, answer, len ); 368 if (ret != len) { 369 D("%s: could not read all of answer %d < %d", 370 __FUNCTION__, ret, len); 371 goto Exit; 372 } 373 374 result = len; 375 376 Exit: 377 close(fd); 378 return result; 379 } 380