Home | History | Annotate | Download | only in qemu
      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