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.
16 #include <libubox/ustream.h>
24 #include <sys/types.h>
27 static inline int setup_tios(int fd
, struct termios
*oldtios
)
29 struct termios newtios
;
35 /* Get current termios */
36 if (tcgetattr(fd
, oldtios
))
41 /* We use the same settings that ssh does. */
42 newtios
.c_iflag
|= IGNPAR
;
43 newtios
.c_iflag
&= ~(ISTRIP
| INLCR
| IGNCR
| ICRNL
| IXON
| IXANY
| IXOFF
);
44 newtios
.c_lflag
&= ~(TOSTOP
| ISIG
| ICANON
| ECHO
| ECHOE
| ECHOK
| ECHONL
);
45 newtios
.c_oflag
&= ~ONLCR
;
46 newtios
.c_oflag
|= OPOST
;
47 newtios
.c_cc
[VMIN
] = 1;
48 newtios
.c_cc
[VTIME
] = 0;
50 /* Set new attributes */
51 if (tcsetattr(fd
, TCSAFLUSH
, &newtios
))
59 #define OPT_ARGS "i:s:"
61 static struct ustream_fd cufd
;
62 static struct ustream_fd lufd
;
66 fprintf(stderr
, "ujail-console -s <service> [-i <instance>]\n");
70 static void client_cb(struct ustream
*s
, int bytes
)
76 buf
= ustream_get_read_buf(s
, &len
);
80 rv
= ustream_write(&lufd
.stream
, buf
, len
, false);
83 ustream_consume(s
, rv
);
90 static void local_cb(struct ustream
*s
, int bytes
)
96 buf
= ustream_get_read_buf(s
, &len
);
100 if ((len
> 0) && (buf
[0] == 2))
103 rv
= ustream_write(&cufd
.stream
, buf
, len
, false);
106 ustream_consume(s
, rv
);
113 int main(int argc
, char **argv
)
115 struct ubus_context
*ctx
;
117 static struct blob_buf req
;
118 char *service_name
= NULL
, *instance_name
= NULL
;
119 int client_fd
, server_fd
, tty_fd
;
120 struct termios oldtermios
;
123 while ((ch
= getopt(argc
, argv
, OPT_ARGS
)) != -1) {
126 instance_name
= optarg
;
129 service_name
= optarg
;
139 ctx
= ubus_connect(NULL
);
141 fprintf(stderr
, "can't connect to ubus!\n");
145 /* open pseudo-terminal pair */
146 client_fd
= posix_openpt(O_RDWR
| O_NOCTTY
);
148 fprintf(stderr
, "can't create virtual console!\n");
152 setup_tios(client_fd
, &oldtermios
);
155 server_fd
= open(ptsname(client_fd
), O_RDWR
| O_NOCTTY
);
157 fprintf(stderr
, "can't open virtual console!\n");
163 setup_tios(server_fd
, &oldtermios
);
164 tty_fd
= open("/dev/tty", O_RDWR
);
165 setup_tios(tty_fd
, &oldtermios
);
167 /* register server-side with procd */
168 blob_buf_init(&req
, 0);
169 blobmsg_add_string(&req
, "name", service_name
);
171 blobmsg_add_string(&req
, "instance", instance_name
);
173 if (ubus_lookup_id(ctx
, "service", &id
) ||
174 ubus_invoke_fd(ctx
, id
, "console_attach", req
.head
, NULL
, NULL
, 3000, server_fd
)) {
175 fprintf(stderr
, "ubus request failed\n");
189 /* forward between stdio and client_fd until detach is requested */
190 lufd
.stream
.notify_read
= local_cb
;
191 ustream_fd_init(&lufd
, tty_fd
);
193 cufd
.stream
.notify_read
= client_cb
;
194 /* ToDo: handle remote close and other events */
195 // cufd.stream.notify_state = client_state_cb;
196 ustream_fd_init(&cufd
, client_fd
);
198 fprintf(stderr
, "attaching to jail console. press [CTRL]+[B] to exit.\n");
204 tcsetattr(tty_fd
, TCSAFLUSH
, &oldtermios
);
205 ustream_free(&lufd
.stream
);
206 ustream_free(&cufd
.stream
);