xref: /qemu/chardev/char-pty.c (revision 7271a81949ee9806705d51618379246fb2b72209)
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  #include "qemu/osdep.h"
25  #include "qapi/error.h"
26  #include "qemu-common.h"
27  #include "chardev/char.h"
28  #include "io/channel-file.h"
29  #include "qemu/sockets.h"
30  #include "qemu/error-report.h"
31  
32  #include "chardev/char-io.h"
33  
34  #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__)      \
35      || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
36      || defined(__GLIBC__)
37  
38  typedef struct {
39      Chardev parent;
40      QIOChannel *ioc;
41      int read_bytes;
42  
43      /* Protected by the Chardev chr_write_lock.  */
44      int connected;
45      guint timer_tag;
46      guint open_tag;
47  } PtyChardev;
48  
49  #define PTY_CHARDEV(obj) OBJECT_CHECK(PtyChardev, (obj), TYPE_CHARDEV_PTY)
50  
51  static void pty_chr_update_read_handler_locked(Chardev *chr);
52  static void pty_chr_state(Chardev *chr, int connected);
53  
54  static gboolean pty_chr_timer(gpointer opaque)
55  {
56      struct Chardev *chr = CHARDEV(opaque);
57      PtyChardev *s = PTY_CHARDEV(opaque);
58  
59      qemu_mutex_lock(&chr->chr_write_lock);
60      s->timer_tag = 0;
61      s->open_tag = 0;
62      if (!s->connected) {
63          /* Next poll ... */
64          pty_chr_update_read_handler_locked(chr);
65      }
66      qemu_mutex_unlock(&chr->chr_write_lock);
67      return FALSE;
68  }
69  
70  /* Called with chr_write_lock held.  */
71  static void pty_chr_rearm_timer(Chardev *chr, int ms)
72  {
73      PtyChardev *s = PTY_CHARDEV(chr);
74      char *name;
75  
76      if (s->timer_tag) {
77          g_source_remove(s->timer_tag);
78          s->timer_tag = 0;
79      }
80  
81      if (ms == 1000) {
82          name = g_strdup_printf("pty-timer-secs-%s", chr->label);
83          s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
84      } else {
85          name = g_strdup_printf("pty-timer-ms-%s", chr->label);
86          s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
87      }
88      g_source_set_name_by_id(s->timer_tag, name);
89      g_free(name);
90  }
91  
92  /* Called with chr_write_lock held.  */
93  static void pty_chr_update_read_handler_locked(Chardev *chr)
94  {
95      PtyChardev *s = PTY_CHARDEV(chr);
96      GPollFD pfd;
97      int rc;
98      QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
99  
100      pfd.fd = fioc->fd;
101      pfd.events = G_IO_OUT;
102      pfd.revents = 0;
103      do {
104          rc = g_poll(&pfd, 1, 0);
105      } while (rc == -1 && errno == EINTR);
106      assert(rc >= 0);
107  
108      if (pfd.revents & G_IO_HUP) {
109          pty_chr_state(chr, 0);
110      } else {
111          pty_chr_state(chr, 1);
112      }
113  }
114  
115  static void pty_chr_update_read_handler(Chardev *chr)
116  {
117      qemu_mutex_lock(&chr->chr_write_lock);
118      pty_chr_update_read_handler_locked(chr);
119      qemu_mutex_unlock(&chr->chr_write_lock);
120  }
121  
122  /* Called with chr_write_lock held.  */
123  static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
124  {
125      PtyChardev *s = PTY_CHARDEV(chr);
126  
127      if (!s->connected) {
128          /* guest sends data, check for (re-)connect */
129          pty_chr_update_read_handler_locked(chr);
130          if (!s->connected) {
131              return len;
132          }
133      }
134      return io_channel_send(s->ioc, buf, len);
135  }
136  
137  static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
138  {
139      PtyChardev *s = PTY_CHARDEV(chr);
140      if (!s->connected) {
141          return NULL;
142      }
143      return qio_channel_create_watch(s->ioc, cond);
144  }
145  
146  static int pty_chr_read_poll(void *opaque)
147  {
148      Chardev *chr = CHARDEV(opaque);
149      PtyChardev *s = PTY_CHARDEV(opaque);
150  
151      s->read_bytes = qemu_chr_be_can_write(chr);
152      return s->read_bytes;
153  }
154  
155  static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
156  {
157      Chardev *chr = CHARDEV(opaque);
158      PtyChardev *s = PTY_CHARDEV(opaque);
159      gsize len;
160      uint8_t buf[CHR_READ_BUF_LEN];
161      ssize_t ret;
162  
163      len = sizeof(buf);
164      if (len > s->read_bytes) {
165          len = s->read_bytes;
166      }
167      if (len == 0) {
168          return TRUE;
169      }
170      ret = qio_channel_read(s->ioc, (char *)buf, len, NULL);
171      if (ret <= 0) {
172          pty_chr_state(chr, 0);
173          return FALSE;
174      } else {
175          pty_chr_state(chr, 1);
176          qemu_chr_be_write(chr, buf, ret);
177      }
178      return TRUE;
179  }
180  
181  static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
182  {
183      Chardev *chr = CHARDEV(opaque);
184      PtyChardev *s = PTY_CHARDEV(opaque);
185  
186      s->open_tag = 0;
187      qemu_chr_be_event(chr, CHR_EVENT_OPENED);
188      return FALSE;
189  }
190  
191  /* Called with chr_write_lock held.  */
192  static void pty_chr_state(Chardev *chr, int connected)
193  {
194      PtyChardev *s = PTY_CHARDEV(chr);
195  
196      if (!connected) {
197          if (s->open_tag) {
198              g_source_remove(s->open_tag);
199              s->open_tag = 0;
200          }
201          remove_fd_in_watch(chr);
202          s->connected = 0;
203          /* (re-)connect poll interval for idle guests: once per second.
204           * We check more frequently in case the guests sends data to
205           * the virtual device linked to our pty. */
206          pty_chr_rearm_timer(chr, 1000);
207      } else {
208          if (s->timer_tag) {
209              g_source_remove(s->timer_tag);
210              s->timer_tag = 0;
211          }
212          if (!s->connected) {
213              g_assert(s->open_tag == 0);
214              s->connected = 1;
215              s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
216          }
217          if (!chr->gsource) {
218              chr->gsource = io_add_watch_poll(chr, s->ioc,
219                                                 pty_chr_read_poll,
220                                                 pty_chr_read,
221                                                 chr, chr->gcontext);
222          }
223      }
224  }
225  
226  static void char_pty_finalize(Object *obj)
227  {
228      Chardev *chr = CHARDEV(obj);
229      PtyChardev *s = PTY_CHARDEV(obj);
230  
231      qemu_mutex_lock(&chr->chr_write_lock);
232      pty_chr_state(chr, 0);
233      object_unref(OBJECT(s->ioc));
234      if (s->timer_tag) {
235          g_source_remove(s->timer_tag);
236          s->timer_tag = 0;
237      }
238      qemu_mutex_unlock(&chr->chr_write_lock);
239      qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
240  }
241  
242  static void char_pty_open(Chardev *chr,
243                            ChardevBackend *backend,
244                            bool *be_opened,
245                            Error **errp)
246  {
247      PtyChardev *s;
248      int master_fd, slave_fd;
249      char pty_name[PATH_MAX];
250      char *name;
251  
252      master_fd = qemu_openpty_raw(&slave_fd, pty_name);
253      if (master_fd < 0) {
254          error_setg_errno(errp, errno, "Failed to create PTY");
255          return;
256      }
257  
258      close(slave_fd);
259      qemu_set_nonblock(master_fd);
260  
261      chr->filename = g_strdup_printf("pty:%s", pty_name);
262      error_report("char device redirected to %s (label %s)",
263                   pty_name, chr->label);
264  
265      s = PTY_CHARDEV(chr);
266      s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
267      name = g_strdup_printf("chardev-pty-%s", chr->label);
268      qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
269      g_free(name);
270      s->timer_tag = 0;
271      *be_opened = false;
272  }
273  
274  static void char_pty_class_init(ObjectClass *oc, void *data)
275  {
276      ChardevClass *cc = CHARDEV_CLASS(oc);
277  
278      cc->open = char_pty_open;
279      cc->chr_write = char_pty_chr_write;
280      cc->chr_update_read_handler = pty_chr_update_read_handler;
281      cc->chr_add_watch = pty_chr_add_watch;
282  }
283  
284  static const TypeInfo char_pty_type_info = {
285      .name = TYPE_CHARDEV_PTY,
286      .parent = TYPE_CHARDEV,
287      .instance_size = sizeof(PtyChardev),
288      .instance_finalize = char_pty_finalize,
289      .class_init = char_pty_class_init,
290  };
291  
292  static void register_types(void)
293  {
294      type_register_static(&char_pty_type_info);
295  }
296  
297  type_init(register_types);
298  
299  #endif
300