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