2 * Copyright (C) 2020 Daniel Golle <daniel@makrotopia.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
20 #include <libubox/ustream.h>
28 #include <sys/types.h>
31 static inline int setup_tios(int fd
, struct termios
*oldtios
)
33 struct termios newtios
;
39 /* Get current termios */
40 if (tcgetattr(fd
, oldtios
))
45 /* We use the same settings that ssh does. */
46 newtios
.c_iflag
|= IGNPAR
;
47 newtios
.c_iflag
&= ~(ISTRIP
| INLCR
| IGNCR
| ICRNL
| IXON
| IXANY
| IXOFF
);
48 newtios
.c_lflag
&= ~(TOSTOP
| ISIG
| ICANON
| ECHO
| ECHOE
| ECHOK
| ECHONL
);
49 newtios
.c_oflag
&= ~ONLCR
;
50 newtios
.c_oflag
|= OPOST
;
51 newtios
.c_cc
[VMIN
] = 1;
52 newtios
.c_cc
[VTIME
] = 0;
54 /* Set new attributes */
55 if (tcsetattr(fd
, TCSAFLUSH
, &newtios
))
63 #define OPT_ARGS "i:c:"
65 static struct ustream_fd cufd
;
66 static struct ustream_fd lufd
;
70 fprintf(stderr
, "ujail-console -c <container> [-i <instance>]\n");
74 static void client_cb(struct ustream
*s
, int bytes
)
80 buf
= ustream_get_read_buf(s
, &len
);
84 rv
= ustream_write(&lufd
.stream
, buf
, len
, false);
87 ustream_consume(s
, rv
);
94 static void local_cb(struct ustream
*s
, int bytes
)
100 buf
= ustream_get_read_buf(s
, &len
);
104 if ((len
> 0) && (buf
[0] == 2))
107 rv
= ustream_write(&cufd
.stream
, buf
, len
, false);
110 ustream_consume(s
, rv
);
117 int main(int argc
, char **argv
)
119 struct ubus_context
*ctx
;
121 static struct blob_buf req
;
122 char *container_name
= NULL
, *instance_name
= NULL
;
123 int client_fd
, server_fd
, tty_fd
;
124 struct termios oldtermios
;
127 while ((ch
= getopt(argc
, argv
, OPT_ARGS
)) != -1) {
130 instance_name
= optarg
;
133 container_name
= optarg
;
143 ctx
= ubus_connect(NULL
);
145 fprintf(stderr
, "can't connect to ubus!\n");
149 /* open pseudo-terminal pair */
150 client_fd
= posix_openpt(O_RDWR
| O_NOCTTY
);
152 fprintf(stderr
, "can't create virtual console!\n");
156 setup_tios(client_fd
, &oldtermios
);
159 server_fd
= open(ptsname(client_fd
), O_RDWR
| O_NOCTTY
);
161 fprintf(stderr
, "can't open virtual console!\n");
166 setup_tios(server_fd
, &oldtermios
);
168 tty_fd
= open("/dev/tty", O_RDWR
);
170 fprintf(stderr
, "can't open local console!\n");
176 setup_tios(tty_fd
, &oldtermios
);
178 /* register server-side with procd */
179 blob_buf_init(&req
, 0);
180 blobmsg_add_string(&req
, "name", container_name
);
182 blobmsg_add_string(&req
, "instance", instance_name
);
184 if (ubus_lookup_id(ctx
, "container", &id
) ||
185 ubus_invoke_fd(ctx
, id
, "console_attach", req
.head
, NULL
, NULL
, 3000, server_fd
)) {
186 fprintf(stderr
, "ubus request failed\n");
200 /* forward between stdio and client_fd until detach is requested */
201 lufd
.stream
.notify_read
= local_cb
;
202 ustream_fd_init(&lufd
, tty_fd
);
204 cufd
.stream
.notify_read
= client_cb
;
205 /* ToDo: handle remote close and other events */
206 // cufd.stream.notify_state = client_state_cb;
207 ustream_fd_init(&cufd
, client_fd
);
209 fprintf(stderr
, "attaching to jail console. press [CTRL]+[B] to exit.\n");
215 tcsetattr(tty_fd
, TCSAFLUSH
, &oldtermios
);
216 ustream_free(&lufd
.stream
);
217 ustream_free(&cufd
.stream
);