]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_console.c
use a default per-container logfile
[mirror_lxc.git] / src / lxc / lxc_console.c
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 */
23
24 #define _GNU_SOURCE
25 #include <stdio.h>
26 #undef _GNU_SOURCE
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <termios.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <libgen.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/poll.h>
39 #include <sys/ioctl.h>
40
41 #include "error.h"
42 #include "lxc.h"
43 #include "log.h"
44 #include "mainloop.h"
45 #include "arguments.h"
46
47 lxc_log_define(lxc_console_ui, lxc_console);
48
49 static 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
56 static int my_parser(struct lxc_arguments* args, int c, char* arg)
57 {
58 switch (c) {
59 case 't': args->ttynum = atoi(arg); break;
60 case 'e': args->escape = etoc(arg); break;
61 }
62 return 0;
63 }
64
65 static const struct option my_longopts[] = {
66 {"tty", required_argument, 0, 't'},
67 {"escape", required_argument, 0, 'e'},
68 LXC_COMMON_OPTIONS
69 };
70
71 static struct lxc_arguments my_args = {
72 .progname = "lxc-console",
73 .help = "\
74 --name=NAME [--tty NUMBER]\n\
75 \n\
76 lxc-console logs on the container with the identifier NAME\n\
77 \n\
78 Options :\n\
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",
82 .options = my_longopts,
83 .parser = my_parser,
84 .checker = NULL,
85 .ttynum = -1,
86 .escape = 1,
87 };
88
89 static int master = -1;
90
91 static void winsz(void)
92 {
93 struct winsize wsz;
94 if (ioctl(0, TIOCGWINSZ, &wsz) == 0)
95 ioctl(master, TIOCSWINSZ, &wsz);
96 }
97
98 static void sigwinch(int sig)
99 {
100 winsz();
101 }
102
103 static int setup_tios(int fd, struct termios *newtios, struct termios *oldtios)
104 {
105 if (!isatty(fd)) {
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
135 static 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 */
147 if (c == my_args.escape && !wait4q) {
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
164 static 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 }
175 r = write(*peer, buf, r);
176
177 return 0;
178 }
179
180 int main(int argc, char *argv[])
181 {
182 int err, std_in = 1;
183 struct lxc_epoll_descr descr;
184 struct termios newtios, oldtios;
185
186 err = lxc_arguments_parse(&my_args, argc, argv);
187 if (err)
188 return -1;
189
190 err = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
191 my_args.progname, my_args.quiet);
192 if (err)
193 return -1;
194
195 err = setup_tios(0, &newtios, &oldtios);
196 if (err) {
197 ERROR("failed to setup tios");
198 return -1;
199 }
200
201 err = lxc_console(my_args.name, my_args.ttynum, &master);
202 if (err)
203 goto out;
204
205 fprintf(stderr, "\n\
206 Type <Ctrl+%1$c q> to exit the console, \
207 <Ctrl+%1$c Ctrl+%1$c> to enter Ctrl+%1$c itself\n",
208 'a' + my_args.escape - 1);
209
210 err = setsid();
211 if (err)
212 INFO("already group leader");
213
214 if (signal(SIGWINCH, sigwinch) == SIG_ERR) {
215 SYSERROR("failed to set SIGWINCH handler");
216 err = -1;
217 goto out;
218 }
219
220 winsz();
221
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;
232 }
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
248 out_mainloop_open:
249 lxc_mainloop_close(&descr);
250
251 out:
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;
261 }