blob: e640354e86ecc71f2e767c7bc70dcba39ba5d548 [file] [log] [blame]
Jeremy Kerrbc1e8932016-04-28 12:27:30 +08001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define _GNU_SOURCE
18
19#include <assert.h>
20#include <err.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <stdlib.h>
Xo Wangc5ef8ea2017-04-17 16:20:43 -070024#include <string.h>
Jeremy Kerrbc1e8932016-04-28 12:27:30 +080025#include <unistd.h>
Xo Wangc5ef8ea2017-04-17 16:20:43 -070026#include <termios.h>
Jeremy Kerrbc1e8932016-04-28 12:27:30 +080027
28#include "console-server.h"
29
30struct tty_handler {
31 struct handler handler;
32 struct console *console;
33 struct poller *poller;
34 int fd;
35};
36
Xo Wangc5ef8ea2017-04-17 16:20:43 -070037struct terminal_speed_name {
38 speed_t speed;
39 const char *name;
40};
41
Jeremy Kerrbc1e8932016-04-28 12:27:30 +080042static struct tty_handler *to_tty_handler(struct handler *handler)
43{
44 return container_of(handler, struct tty_handler, handler);
45}
46
47static enum poller_ret tty_poll(struct handler *handler,
48 int events, void __attribute__((unused)) *data)
49{
50 struct tty_handler *th = to_tty_handler(handler);
51 uint8_t buf[4096];
52 ssize_t len;
53
54 if (!(events & POLLIN))
55 return POLLER_OK;
56
57 len = read(th->fd, buf, sizeof(buf));
58 if (len <= 0) {
59 th->poller = NULL;
60 close(th->fd);
61 return POLLER_REMOVE;
62 }
63
64 console_data_out(th->console, buf, len);
65
66 return POLLER_OK;
67}
68
Xo Wangc5ef8ea2017-04-17 16:20:43 -070069static int baud_string_to_speed(speed_t *speed, const char *baud_string) {
70 const struct terminal_speed_name terminal_speeds[] = {
71 { B50, "50" },
72 { B75, "75" },
73 { B110, "110" },
74 { B134, "134" },
75 { B150, "150" },
76 { B200, "200" },
77 { B300, "300" },
78 { B600, "600" },
79 { B1200, "1200" },
80 { B1800, "1800" },
81 { B2400, "2400" },
82 { B4800, "4800" },
83 { B9600, "9600" },
84 { B19200, "19200" },
85 { B38400, "38400" },
86 { B57600, "57600" },
87 { B115200, "115200" },
88 { B230400, "230400" },
89 { B460800, "460800" },
90 { B500000, "500000" },
91 { B576000, "576000" },
92 { B921600, "921600" },
93 { B1000000, "1000000" },
94 { B1152000, "1152000" },
95 { B1500000, "1500000" },
96 { B2000000, "2000000" },
97 { B2500000, "2500000" },
98 { B3000000, "3000000" },
99 { B3500000, "3500000" },
100 { B4000000, "4000000" },
101 };
102 const size_t num_terminal_speeds = sizeof(terminal_speeds) /
103 sizeof(struct terminal_speed_name);
104 size_t i;
105
106 for (i = 0; i < num_terminal_speeds; i++) {
107 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
108 *speed = terminal_speeds[i].speed;
109 return 0;
110 }
111 }
112 return -1;
113}
114
115static int set_terminal_baud(struct tty_handler *th, const char *tty_name,
116 const char *desired_baud) {
117 struct termios term_options;
118 speed_t speed;
119
120 if (baud_string_to_speed(&speed, desired_baud) != 0) {
121 fprintf(stderr, "%s is not a valid baud rate for terminal %s\n",
122 desired_baud, tty_name);
123 return -1;
124 }
125
126 if (tcgetattr(th->fd, &term_options) < 0) {
127 warn("Can't get config for %s", tty_name);
128 return -1;
129 }
130
131 if (cfsetspeed(&term_options, speed) < 0) {
132 warn("Couldn't set speeds for %s", tty_name);
133 return -1;
134 }
135
136 if (tcsetattr(th->fd, TCSAFLUSH, &term_options) < 0) {
137 warn("Couldn't commit terminal options for %s", tty_name);
138 return -1;
139 }
140 printf("Set %s terminal baud rate to %s\n", tty_name, desired_baud);
141
142 return 0;
143}
144
Jeremy Kerrbc1e8932016-04-28 12:27:30 +0800145static int tty_init(struct handler *handler, struct console *console,
146 struct config *config __attribute__((unused)))
147{
148 struct tty_handler *th = to_tty_handler(handler);
149 const char *tty_name;
Xo Wangc5ef8ea2017-04-17 16:20:43 -0700150 const char *tty_baud;
Jeremy Kerrbc1e8932016-04-28 12:27:30 +0800151 char *tty_path;
152 int rc, flags;
153
154 tty_name = config_get_value(config, "local-tty");
155 if (!tty_name)
156 return -1;
157
158 rc = asprintf(&tty_path, "/dev/%s", tty_name);
159 if (!rc)
160 return -1;
161
162 th->fd = open(tty_path, O_RDWR);
163 if (th->fd < 0) {
164 warn("Can't open %s; disabling local tty", tty_name);
165 free(tty_path);
166 return -1;
167 }
168
169 free(tty_path);
170
171 /* initial tty setup */
172 flags = fcntl(th->fd, F_GETFL, 0);
173 flags |= FNDELAY;
174 fcntl(th->fd, F_SETFL, flags);
175
Xo Wangc5ef8ea2017-04-17 16:20:43 -0700176 tty_baud = config_get_value(config, "local-tty-baud");
177 if (tty_baud != NULL)
178 if (set_terminal_baud(th, tty_name, tty_baud) != 0)
179 fprintf(stderr, "Couldn't set baud rate for %s to %s\n",
180 tty_name, tty_baud);
181
Jeremy Kerrbc1e8932016-04-28 12:27:30 +0800182 th->poller = console_register_poller(console, handler, tty_poll,
183 th->fd, POLLIN, NULL);
184 th->console = console;
185
186 return 0;
187}
188
189static int tty_data(struct handler *handler, uint8_t *buf, size_t len)
190{
191 struct tty_handler *th = to_tty_handler(handler);
192 return write_buf_to_fd(th->fd, buf, len);
193}
194
195static void tty_fini(struct handler *handler)
196{
197 struct tty_handler *th = to_tty_handler(handler);
198 if (th->poller)
199 console_unregister_poller(th->console, th->poller);
200 close(th->fd);
201}
202
203static struct tty_handler tty_handler = {
204 .handler = {
205 .name = "tty",
206 .init = tty_init,
207 .data_in = tty_data,
208 .fini = tty_fini,
209 },
210};
211
212console_register_handler(&tty_handler.handler);
213