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