]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_console.c
use a default per-container logfile
[mirror_lxc.git] / src / lxc / lxc_console.c
CommitLineData
5e97c3fc 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
b0a33c1e 23
24#define _GNU_SOURCE
5e97c3fc 25#include <stdio.h>
b0a33c1e 26#undef _GNU_SOURCE
27#include <stdlib.h>
28#include <errno.h>
29#include <string.h>
30#include <fcntl.h>
31#include <termios.h>
5e97c3fc 32#include <unistd.h>
b0a33c1e 33#include <signal.h>
34#include <libgen.h>
35#include <sys/param.h>
5e97c3fc 36#include <sys/types.h>
b0a33c1e 37#include <sys/stat.h>
38#include <sys/poll.h>
994f905e 39#include <sys/ioctl.h>
5e97c3fc 40
7ee5bb55
DL
41#include "error.h"
42#include "lxc.h"
43#include "log.h"
44#include "mainloop.h"
41cfbac9 45#include "arguments.h"
36eb9bde 46
77075659 47lxc_log_define(lxc_console_ui, lxc_console);
5e97c3fc 48
84a24de2
TY
49static char etoc(const char *expr)
50{
51 /* returns "control code" of given expression */
52 char c = expr[0] == '^' ? expr[1] : expr[0];
53 return 1 + ((c > 'Z') ? (c - 'a') : (c - 'Z'));
54}
55
41cfbac9 56static int my_parser(struct lxc_arguments* args, int c, char* arg)
5e97c3fc 57{
41cfbac9
MN
58 switch (c) {
59 case 't': args->ttynum = atoi(arg); break;
84a24de2 60 case 'e': args->escape = etoc(arg); break;
41cfbac9
MN
61 }
62 return 0;
5e97c3fc 63}
64
41cfbac9
MN
65static const struct option my_longopts[] = {
66 {"tty", required_argument, 0, 't'},
84a24de2 67 {"escape", required_argument, 0, 'e'},
41cfbac9
MN
68 LXC_COMMON_OPTIONS
69};
70
71static struct lxc_arguments my_args = {
72 .progname = "lxc-console",
73 .help = "\
74--name=NAME [--tty NUMBER]\n\
75\n\
76lxc-console logs on the container with the identifier NAME\n\
77\n\
78Options :\n\
84a24de2
TY
79 -n, --name=NAME NAME for name of the container\n\
80 -t, --tty=NUMBER console tty number\n\
81 -e, --escape=PREFIX prefix for escape command\n",
41cfbac9
MN
82 .options = my_longopts,
83 .parser = my_parser,
84 .checker = NULL,
85 .ttynum = -1,
84a24de2 86 .escape = 1,
41cfbac9
MN
87};
88
994f905e
MT
89static int master = -1;
90
91static void winsz(void)
92{
93 struct winsize wsz;
94 if (ioctl(0, TIOCGWINSZ, &wsz) == 0)
95 ioctl(master, TIOCSWINSZ, &wsz);
96}
97
98static void sigwinch(int sig)
99{
100 winsz();
101}
102
6dae6815
DL
103static int setup_tios(int fd, struct termios *newtios, struct termios *oldtios)
104{
7ee5bb55 105 if (!isatty(fd)) {
6dae6815
DL
106 ERROR("'%d' is not a tty", fd);
107 return -1;
108 }
109
110 /* Get current termios */
111 if (tcgetattr(0, oldtios)) {
112 SYSERROR("failed to get current terminal settings");
113 return -1;
114 }
115
116 *newtios = *oldtios;
117
118 /* Remove the echo characters and signal reception, the echo
119 * will be done below with master proxying */
120 newtios->c_iflag &= ~IGNBRK;
121 newtios->c_iflag &= BRKINT;
122 newtios->c_lflag &= ~(ECHO|ICANON|ISIG);
123 newtios->c_cc[VMIN] = 1;
124 newtios->c_cc[VTIME] = 0;
125
126 /* Set new attributes */
127 if (tcsetattr(0, TCSAFLUSH, newtios)) {
128 ERROR("failed to set new terminal settings");
129 return -1;
130 }
131
132 return 0;
133}
134
7ee5bb55
DL
135static int stdin_handler(int fd, void *data, struct lxc_epoll_descr *descr)
136{
137 static int wait4q = 0;
138 int *peer = (int *)data;
139 char c;
140
141 if (read(0, &c, 1) < 0) {
142 SYSERROR("failed to read");
143 return 1;
144 }
145
146 /* we want to exit the console with Ctrl+a q */
3f52fd07 147 if (c == my_args.escape && !wait4q) {
7ee5bb55
DL
148 wait4q = !wait4q;
149 return 0;
150 }
151
152 if (c == 'q' && wait4q)
153 return 1;
154
155 wait4q = 0;
156 if (write(*peer, &c, 1) < 0) {
157 SYSERROR("failed to write");
158 return 1;
159 }
160
161 return 0;
162}
163
164static int master_handler(int fd, void *data, struct lxc_epoll_descr *descr)
165{
166 char buf[1024];
167 int *peer = (int *)data;
168 int r;
169
170 r = read(fd, buf, sizeof(buf));
171 if (r < 0) {
172 SYSERROR("failed to read");
173 return 1;
174 }
5fad0874 175 r = write(*peer, buf, r);
7ee5bb55
DL
176
177 return 0;
178}
179
b0a33c1e 180int main(int argc, char *argv[])
181{
7ee5bb55
DL
182 int err, std_in = 1;
183 struct lxc_epoll_descr descr;
6dae6815 184 struct termios newtios, oldtios;
b0a33c1e 185
41cfbac9
MN
186 err = lxc_arguments_parse(&my_args, argc, argv);
187 if (err)
2ea004b8 188 return -1;
b0a33c1e 189
5e1e7aaf 190 err = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
7ee5bb55
DL
191 my_args.progname, my_args.quiet);
192 if (err)
2ea004b8 193 return -1;
51cab631 194
7ee5bb55
DL
195 err = setup_tios(0, &newtios, &oldtios);
196 if (err) {
6dae6815 197 ERROR("failed to setup tios");
2ea004b8 198 return -1;
b0a33c1e 199 }
200
41cfbac9 201 err = lxc_console(my_args.name, my_args.ttynum, &master);
3ab87b66 202 if (err)
b0a33c1e 203 goto out;
b0a33c1e 204
3f52fd07
IVB
205 fprintf(stderr, "\n\
206Type <Ctrl+%1$c q> to exit the console, \
207<Ctrl+%1$c Ctrl+%1$c> to enter Ctrl+%1$c itself\n",
84a24de2 208 'a' + my_args.escape - 1);
b0a33c1e 209
7ee5bb55
DL
210 err = setsid();
211 if (err)
6dae6815
DL
212 INFO("already group leader");
213
214 if (signal(SIGWINCH, sigwinch) == SIG_ERR) {
215 SYSERROR("failed to set SIGWINCH handler");
7ee5bb55
DL
216 err = -1;
217 goto out;
6dae6815
DL
218 }
219
994f905e 220 winsz();
b0a33c1e 221
7ee5bb55
DL
222 err = lxc_mainloop_open(&descr);
223 if (err) {
224 ERROR("failed to create mainloop");
225 goto out;
226 }
227
228 err = lxc_mainloop_add_handler(&descr, 0, stdin_handler, &master);
229 if (err) {
230 ERROR("failed to add handler for the stdin");
231 goto out_mainloop_open;
b0a33c1e 232 }
7ee5bb55
DL
233
234 err = lxc_mainloop_add_handler(&descr, master, master_handler, &std_in);
235 if (err) {
236 ERROR("failed to add handler for the master");
237 goto out_mainloop_open;
238 }
239
240 err = lxc_mainloop(&descr);
241 if (err) {
242 ERROR("mainloop returned an error");
243 goto out_mainloop_open;
244 }
245
246 err = 0;
247
248out_mainloop_open:
249 lxc_mainloop_close(&descr);
250
b0a33c1e 251out:
252 /* Restore previous terminal parameter */
253 tcsetattr(0, TCSAFLUSH, &oldtios);
254
255 /* Return to line it is */
256 printf("\n");
257
258 close(master);
259
260 return err;
b0a33c1e 261}