qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

char-pty.c (9449B)


      1 /*
      2  * QEMU System Emulator
      3  *
      4  * Copyright (c) 2003-2008 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "qapi/error.h"
     27 #include "chardev/char.h"
     28 #include "io/channel-file.h"
     29 #include "qemu/sockets.h"
     30 #include "qemu/error-report.h"
     31 #include "qemu/module.h"
     32 #include "qemu/qemu-print.h"
     33 
     34 #include "chardev/char-io.h"
     35 #include "qom/object.h"
     36 
     37 struct PtyChardev {
     38     Chardev parent;
     39     QIOChannel *ioc;
     40     int read_bytes;
     41 
     42     int connected;
     43     GSource *timer_src;
     44 };
     45 typedef struct PtyChardev PtyChardev;
     46 
     47 DECLARE_INSTANCE_CHECKER(PtyChardev, PTY_CHARDEV,
     48                          TYPE_CHARDEV_PTY)
     49 
     50 static void pty_chr_state(Chardev *chr, int connected);
     51 
     52 static void pty_chr_timer_cancel(PtyChardev *s)
     53 {
     54     if (s->timer_src) {
     55         g_source_destroy(s->timer_src);
     56         g_source_unref(s->timer_src);
     57         s->timer_src = NULL;
     58     }
     59 }
     60 
     61 static gboolean pty_chr_timer(gpointer opaque)
     62 {
     63     struct Chardev *chr = CHARDEV(opaque);
     64     PtyChardev *s = PTY_CHARDEV(opaque);
     65 
     66     pty_chr_timer_cancel(s);
     67     if (!s->connected) {
     68         /* Next poll ... */
     69         qemu_chr_be_update_read_handlers(chr, chr->gcontext);
     70     }
     71     return FALSE;
     72 }
     73 
     74 static void pty_chr_rearm_timer(Chardev *chr, int ms)
     75 {
     76     PtyChardev *s = PTY_CHARDEV(chr);
     77     char *name;
     78 
     79     pty_chr_timer_cancel(s);
     80     name = g_strdup_printf("pty-timer-%s", chr->label);
     81     s->timer_src = qemu_chr_timeout_add_ms(chr, ms, pty_chr_timer, chr);
     82     g_source_set_name(s->timer_src, name);
     83     g_free(name);
     84 }
     85 
     86 static void pty_chr_update_read_handler(Chardev *chr)
     87 {
     88     PtyChardev *s = PTY_CHARDEV(chr);
     89     GPollFD pfd;
     90     int rc;
     91     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
     92 
     93     pfd.fd = fioc->fd;
     94     pfd.events = G_IO_OUT;
     95     pfd.revents = 0;
     96     do {
     97         rc = g_poll(&pfd, 1, 0);
     98     } while (rc == -1 && errno == EINTR);
     99     assert(rc >= 0);
    100 
    101     if (pfd.revents & G_IO_HUP) {
    102         pty_chr_state(chr, 0);
    103     } else {
    104         pty_chr_state(chr, 1);
    105     }
    106 }
    107 
    108 static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
    109 {
    110     PtyChardev *s = PTY_CHARDEV(chr);
    111 
    112     if (!s->connected) {
    113         return len;
    114     }
    115     return io_channel_send(s->ioc, buf, len);
    116 }
    117 
    118 static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
    119 {
    120     PtyChardev *s = PTY_CHARDEV(chr);
    121     if (!s->connected) {
    122         return NULL;
    123     }
    124     return qio_channel_create_watch(s->ioc, cond);
    125 }
    126 
    127 static int pty_chr_read_poll(void *opaque)
    128 {
    129     Chardev *chr = CHARDEV(opaque);
    130     PtyChardev *s = PTY_CHARDEV(opaque);
    131 
    132     s->read_bytes = qemu_chr_be_can_write(chr);
    133     return s->read_bytes;
    134 }
    135 
    136 static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
    137 {
    138     Chardev *chr = CHARDEV(opaque);
    139     PtyChardev *s = PTY_CHARDEV(opaque);
    140     gsize len;
    141     uint8_t buf[CHR_READ_BUF_LEN];
    142     ssize_t ret;
    143 
    144     len = sizeof(buf);
    145     if (len > s->read_bytes) {
    146         len = s->read_bytes;
    147     }
    148     if (len == 0) {
    149         return TRUE;
    150     }
    151     ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
    152     if (ret <= 0) {
    153         pty_chr_state(chr, 0);
    154         return FALSE;
    155     } else {
    156         pty_chr_state(chr, 1);
    157         qemu_chr_be_write(chr, buf, ret);
    158     }
    159     return TRUE;
    160 }
    161 
    162 static void pty_chr_state(Chardev *chr, int connected)
    163 {
    164     PtyChardev *s = PTY_CHARDEV(chr);
    165 
    166     if (!connected) {
    167         remove_fd_in_watch(chr);
    168         s->connected = 0;
    169         /* (re-)connect poll interval for idle guests: once per second.
    170          * We check more frequently in case the guests sends data to
    171          * the virtual device linked to our pty. */
    172         pty_chr_rearm_timer(chr, 1000);
    173     } else {
    174         pty_chr_timer_cancel(s);
    175         if (!s->connected) {
    176             s->connected = 1;
    177             qemu_chr_be_event(chr, CHR_EVENT_OPENED);
    178         }
    179         if (!chr->gsource) {
    180             chr->gsource = io_add_watch_poll(chr, s->ioc,
    181                                                pty_chr_read_poll,
    182                                                pty_chr_read,
    183                                                chr, chr->gcontext);
    184         }
    185     }
    186 }
    187 
    188 static void char_pty_finalize(Object *obj)
    189 {
    190     Chardev *chr = CHARDEV(obj);
    191     PtyChardev *s = PTY_CHARDEV(obj);
    192 
    193     pty_chr_state(chr, 0);
    194     object_unref(OBJECT(s->ioc));
    195     pty_chr_timer_cancel(s);
    196     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    197 }
    198 
    199 #if defined HAVE_PTY_H
    200 # include <pty.h>
    201 #elif defined CONFIG_BSD
    202 # include <termios.h>
    203 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
    204 #  include <libutil.h>
    205 # else
    206 #  include <util.h>
    207 # endif
    208 #elif defined CONFIG_SOLARIS
    209 # include <termios.h>
    210 # include <stropts.h>
    211 #else
    212 # include <termios.h>
    213 #endif
    214 
    215 #ifdef __sun__
    216 
    217 #if !defined(HAVE_OPENPTY)
    218 /* Once illumos has openpty(), this is going to be removed. */
    219 static int openpty(int *amaster, int *aslave, char *name,
    220                    struct termios *termp, struct winsize *winp)
    221 {
    222     const char *slave;
    223     int mfd = -1, sfd = -1;
    224 
    225     *amaster = *aslave = -1;
    226 
    227     mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
    228     if (mfd < 0) {
    229         goto err;
    230     }
    231 
    232     if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) {
    233         goto err;
    234     }
    235 
    236     if ((slave = ptsname(mfd)) == NULL) {
    237         goto err;
    238     }
    239 
    240     if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) {
    241         goto err;
    242     }
    243 
    244     if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
    245         (termp != NULL && tcgetattr(sfd, termp) < 0)) {
    246         goto err;
    247     }
    248 
    249     *amaster = mfd;
    250     *aslave = sfd;
    251 
    252     if (winp) {
    253         ioctl(sfd, TIOCSWINSZ, winp);
    254     }
    255 
    256     return 0;
    257 
    258 err:
    259     if (sfd != -1) {
    260         close(sfd);
    261     }
    262     close(mfd);
    263     return -1;
    264 }
    265 #endif
    266 
    267 static void cfmakeraw (struct termios *termios_p)
    268 {
    269     termios_p->c_iflag &=
    270         ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    271     termios_p->c_oflag &= ~OPOST;
    272     termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    273     termios_p->c_cflag &= ~(CSIZE | PARENB);
    274     termios_p->c_cflag |= CS8;
    275 
    276     termios_p->c_cc[VMIN] = 0;
    277     termios_p->c_cc[VTIME] = 0;
    278 }
    279 #endif
    280 
    281 /* like openpty() but also makes it raw; return master fd */
    282 static int qemu_openpty_raw(int *aslave, char *pty_name)
    283 {
    284     int amaster;
    285     struct termios tty;
    286 #if defined(__OpenBSD__) || defined(__DragonFly__)
    287     char pty_buf[PATH_MAX];
    288 #define q_ptsname(x) pty_buf
    289 #else
    290     char *pty_buf = NULL;
    291 #define q_ptsname(x) ptsname(x)
    292 #endif
    293 
    294     if (openpty(&amaster, aslave, pty_buf, NULL, NULL) < 0) {
    295         return -1;
    296     }
    297 
    298     /* Set raw attributes on the pty. */
    299     tcgetattr(*aslave, &tty);
    300     cfmakeraw(&tty);
    301     tcsetattr(*aslave, TCSAFLUSH, &tty);
    302 
    303     if (pty_name) {
    304         strcpy(pty_name, q_ptsname(amaster));
    305     }
    306 
    307     return amaster;
    308 }
    309 
    310 static void char_pty_open(Chardev *chr,
    311                           ChardevBackend *backend,
    312                           bool *be_opened,
    313                           Error **errp)
    314 {
    315     PtyChardev *s;
    316     int master_fd, slave_fd;
    317     char pty_name[PATH_MAX];
    318     char *name;
    319 
    320     master_fd = qemu_openpty_raw(&slave_fd, pty_name);
    321     if (master_fd < 0) {
    322         error_setg_errno(errp, errno, "Failed to create PTY");
    323         return;
    324     }
    325 
    326     close(slave_fd);
    327     if (!g_unix_set_fd_nonblocking(master_fd, true, NULL)) {
    328         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
    329         return;
    330     }
    331 
    332     chr->filename = g_strdup_printf("pty:%s", pty_name);
    333     qemu_printf("char device redirected to %s (label %s)\n",
    334                 pty_name, chr->label);
    335 
    336     s = PTY_CHARDEV(chr);
    337     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
    338     name = g_strdup_printf("chardev-pty-%s", chr->label);
    339     qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
    340     g_free(name);
    341     s->timer_src = NULL;
    342     *be_opened = false;
    343 }
    344 
    345 static void char_pty_class_init(ObjectClass *oc, void *data)
    346 {
    347     ChardevClass *cc = CHARDEV_CLASS(oc);
    348 
    349     cc->open = char_pty_open;
    350     cc->chr_write = char_pty_chr_write;
    351     cc->chr_update_read_handler = pty_chr_update_read_handler;
    352     cc->chr_add_watch = pty_chr_add_watch;
    353 }
    354 
    355 static const TypeInfo char_pty_type_info = {
    356     .name = TYPE_CHARDEV_PTY,
    357     .parent = TYPE_CHARDEV,
    358     .instance_size = sizeof(PtyChardev),
    359     .instance_finalize = char_pty_finalize,
    360     .class_init = char_pty_class_init,
    361 };
    362 
    363 static void register_types(void)
    364 {
    365     type_register_static(&char_pty_type_info);
    366 }
    367 
    368 type_init(register_types);