1d1800815SMarc-André Lureau /*
2d1800815SMarc-André Lureau * QEMU System Emulator
3d1800815SMarc-André Lureau *
4d1800815SMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard
5d1800815SMarc-André Lureau *
6d1800815SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
7d1800815SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
8d1800815SMarc-André Lureau * in the Software without restriction, including without limitation the rights
9d1800815SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10d1800815SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
11d1800815SMarc-André Lureau * furnished to do so, subject to the following conditions:
12d1800815SMarc-André Lureau *
13d1800815SMarc-André Lureau * The above copyright notice and this permission notice shall be included in
14d1800815SMarc-André Lureau * all copies or substantial portions of the Software.
15d1800815SMarc-André Lureau *
16d1800815SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d1800815SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d1800815SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19d1800815SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d1800815SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21d1800815SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22d1800815SMarc-André Lureau * THE SOFTWARE.
23d1800815SMarc-André Lureau */
24922a01a0SMarkus Armbruster
25d1800815SMarc-André Lureau #include "qemu/osdep.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27922a01a0SMarkus Armbruster #include "qemu/option.h"
28d1800815SMarc-André Lureau #include "qemu/sockets.h"
29d1800815SMarc-André Lureau #include "qapi/error.h"
308228e353SMarc-André Lureau #include "chardev/char.h"
31d1800815SMarc-André Lureau
32d1800815SMarc-André Lureau #ifdef _WIN32
338228e353SMarc-André Lureau #include "chardev/char-win.h"
348228e353SMarc-André Lureau #include "chardev/char-win-stdio.h"
35d1800815SMarc-André Lureau #else
36d1800815SMarc-André Lureau #include <termios.h>
378228e353SMarc-André Lureau #include "chardev/char-fd.h"
38d1800815SMarc-André Lureau #endif
39d1800815SMarc-André Lureau
40d1800815SMarc-André Lureau #ifndef _WIN32
41d1800815SMarc-André Lureau /* init terminal so that we can grab keys */
42d1800815SMarc-André Lureau static struct termios oldtty;
43d1800815SMarc-André Lureau static int old_fd0_flags;
44*a0124e33SMaxim Mikityanskiy static int old_fd1_flags;
45d1800815SMarc-André Lureau static bool stdio_in_use;
46d1800815SMarc-André Lureau static bool stdio_allow_signal;
47d1800815SMarc-André Lureau static bool stdio_echo_state;
48d1800815SMarc-André Lureau
term_exit(void)49d1800815SMarc-André Lureau static void term_exit(void)
50d1800815SMarc-André Lureau {
511507bd13SDaniel P. Berrangé if (stdio_in_use) {
52d1800815SMarc-André Lureau tcsetattr(0, TCSANOW, &oldtty);
53d1800815SMarc-André Lureau fcntl(0, F_SETFL, old_fd0_flags);
54*a0124e33SMaxim Mikityanskiy fcntl(1, F_SETFL, old_fd1_flags);
55*a0124e33SMaxim Mikityanskiy stdio_in_use = false;
56d1800815SMarc-André Lureau }
571507bd13SDaniel P. Berrangé }
58d1800815SMarc-André Lureau
qemu_chr_set_echo_stdio(Chardev * chr,bool echo)59d1800815SMarc-André Lureau static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
60d1800815SMarc-André Lureau {
61d1800815SMarc-André Lureau struct termios tty;
62d1800815SMarc-André Lureau
63d1800815SMarc-André Lureau stdio_echo_state = echo;
64d1800815SMarc-André Lureau tty = oldtty;
65d1800815SMarc-André Lureau if (!echo) {
66d1800815SMarc-André Lureau tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
67d1800815SMarc-André Lureau | INLCR | IGNCR | ICRNL | IXON);
68ed6b018eSPhilippe Mathieu-Daudé tty.c_oflag |= OPOST;
69d1800815SMarc-André Lureau tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
70d1800815SMarc-André Lureau tty.c_cflag &= ~(CSIZE | PARENB);
71d1800815SMarc-André Lureau tty.c_cflag |= CS8;
72d1800815SMarc-André Lureau tty.c_cc[VMIN] = 1;
73d1800815SMarc-André Lureau tty.c_cc[VTIME] = 0;
74d1800815SMarc-André Lureau }
75d1800815SMarc-André Lureau if (!stdio_allow_signal) {
76d1800815SMarc-André Lureau tty.c_lflag &= ~ISIG;
77d1800815SMarc-André Lureau }
78d1800815SMarc-André Lureau
79d1800815SMarc-André Lureau tcsetattr(0, TCSANOW, &tty);
80d1800815SMarc-André Lureau }
81d1800815SMarc-André Lureau
term_stdio_handler(int sig)82d1800815SMarc-André Lureau static void term_stdio_handler(int sig)
83d1800815SMarc-André Lureau {
84d1800815SMarc-André Lureau /* restore echo after resume from suspend. */
85d1800815SMarc-André Lureau qemu_chr_set_echo_stdio(NULL, stdio_echo_state);
86d1800815SMarc-André Lureau }
87d1800815SMarc-André Lureau
qemu_chr_open_stdio(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)88d1800815SMarc-André Lureau static void qemu_chr_open_stdio(Chardev *chr,
89d1800815SMarc-André Lureau ChardevBackend *backend,
90d1800815SMarc-André Lureau bool *be_opened,
91d1800815SMarc-André Lureau Error **errp)
92d1800815SMarc-André Lureau {
93d1800815SMarc-André Lureau ChardevStdio *opts = backend->u.stdio.data;
94d1800815SMarc-André Lureau struct sigaction act;
95d1800815SMarc-André Lureau
96d1800815SMarc-André Lureau if (is_daemonized()) {
97d1800815SMarc-André Lureau error_setg(errp, "cannot use stdio with -daemonize");
98d1800815SMarc-André Lureau return;
99d1800815SMarc-André Lureau }
100d1800815SMarc-André Lureau
101d1800815SMarc-André Lureau if (stdio_in_use) {
102d1800815SMarc-André Lureau error_setg(errp, "cannot use stdio by multiple character devices");
103d1800815SMarc-André Lureau return;
104d1800815SMarc-André Lureau }
105d1800815SMarc-André Lureau
106d1800815SMarc-André Lureau stdio_in_use = true;
107d1800815SMarc-André Lureau old_fd0_flags = fcntl(0, F_GETFL);
108*a0124e33SMaxim Mikityanskiy old_fd1_flags = fcntl(1, F_GETFL);
109d1800815SMarc-André Lureau tcgetattr(0, &oldtty);
110b84bb4dfSMarc-André Lureau if (!g_unix_set_fd_nonblocking(0, true, NULL)) {
111b84bb4dfSMarc-André Lureau error_setg_errno(errp, errno, "Failed to set FD nonblocking");
112b84bb4dfSMarc-André Lureau return;
113b84bb4dfSMarc-André Lureau }
114d1800815SMarc-André Lureau atexit(term_exit);
115d1800815SMarc-André Lureau
116d1800815SMarc-André Lureau memset(&act, 0, sizeof(act));
117d1800815SMarc-André Lureau act.sa_handler = term_stdio_handler;
118d1800815SMarc-André Lureau sigaction(SIGCONT, &act, NULL);
119d1800815SMarc-André Lureau
120d1800815SMarc-André Lureau qemu_chr_open_fd(chr, 0, 1);
121d1800815SMarc-André Lureau
1226deb20f6SKevin Wolf stdio_allow_signal = !opts->has_signal || opts->signal;
123d1800815SMarc-André Lureau qemu_chr_set_echo_stdio(chr, false);
124d1800815SMarc-André Lureau }
125d1800815SMarc-André Lureau #endif
126d1800815SMarc-André Lureau
qemu_chr_parse_stdio(QemuOpts * opts,ChardevBackend * backend,Error ** errp)127d1800815SMarc-André Lureau static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend,
128d1800815SMarc-André Lureau Error **errp)
129d1800815SMarc-André Lureau {
130d1800815SMarc-André Lureau ChardevStdio *stdio;
131d1800815SMarc-André Lureau
132d1800815SMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_STDIO;
133d1800815SMarc-André Lureau stdio = backend->u.stdio.data = g_new0(ChardevStdio, 1);
134d1800815SMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevStdio_base(stdio));
135d1800815SMarc-André Lureau stdio->has_signal = true;
136d1800815SMarc-André Lureau stdio->signal = qemu_opt_get_bool(opts, "signal", true);
137d1800815SMarc-André Lureau }
138d1800815SMarc-André Lureau
char_stdio_class_init(ObjectClass * oc,void * data)139d1800815SMarc-André Lureau static void char_stdio_class_init(ObjectClass *oc, void *data)
140d1800815SMarc-André Lureau {
141d1800815SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
142d1800815SMarc-André Lureau
143d1800815SMarc-André Lureau cc->parse = qemu_chr_parse_stdio;
144d1800815SMarc-André Lureau #ifndef _WIN32
145d1800815SMarc-André Lureau cc->open = qemu_chr_open_stdio;
146d1800815SMarc-André Lureau cc->chr_set_echo = qemu_chr_set_echo_stdio;
147d1800815SMarc-André Lureau #endif
148d1800815SMarc-André Lureau }
149d1800815SMarc-André Lureau
char_stdio_finalize(Object * obj)150d1800815SMarc-André Lureau static void char_stdio_finalize(Object *obj)
151d1800815SMarc-André Lureau {
152d1800815SMarc-André Lureau #ifndef _WIN32
153d1800815SMarc-André Lureau term_exit();
154d1800815SMarc-André Lureau #endif
155d1800815SMarc-André Lureau }
156d1800815SMarc-André Lureau
157d1800815SMarc-André Lureau static const TypeInfo char_stdio_type_info = {
158d1800815SMarc-André Lureau .name = TYPE_CHARDEV_STDIO,
159d1800815SMarc-André Lureau #ifdef _WIN32
160d1800815SMarc-André Lureau .parent = TYPE_CHARDEV_WIN_STDIO,
161d1800815SMarc-André Lureau #else
162d1800815SMarc-André Lureau .parent = TYPE_CHARDEV_FD,
163d1800815SMarc-André Lureau #endif
164d1800815SMarc-André Lureau .instance_finalize = char_stdio_finalize,
165d1800815SMarc-André Lureau .class_init = char_stdio_class_init,
166d1800815SMarc-André Lureau };
167d1800815SMarc-André Lureau
register_types(void)168d1800815SMarc-André Lureau static void register_types(void)
169d1800815SMarc-André Lureau {
170d1800815SMarc-André Lureau type_register_static(&char_stdio_type_info);
171d1800815SMarc-André Lureau }
172d1800815SMarc-André Lureau
173d1800815SMarc-André Lureau type_init(register_types);
174