]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
allocate a console to be proxied
[mirror_lxc.git] / src / lxc / console.c
CommitLineData
b0a33c1e 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#include <stdio.h>
25#include <unistd.h>
63376d7d 26#include <fcntl.h>
b0a33c1e 27#include <errno.h>
63376d7d 28#include <pty.h>
b0a33c1e 29#include <sys/types.h>
30#include <sys/un.h>
31
00b3c2e2
CLG
32#include <lxc/log.h>
33#include <lxc/conf.h>
34#include <lxc/start.h> /* for struct lxc_handler */
35
96fa1ff0 36#include "commands.h"
63376d7d 37#include "mainloop.h"
724e753c 38#include "af_unix.h"
36eb9bde
CLG
39
40lxc_log_define(lxc_console, lxc);
41
96fa1ff0
MN
42extern int lxc_console(const char *name, int ttynum, int *fd)
43{
d97b36f8 44 int ret, stopped = 0;
96fa1ff0
MN
45 struct lxc_command command = {
46 .request = { .type = LXC_COMMAND_TTY, .data = ttynum },
47 };
48
d97b36f8
DL
49 ret = lxc_command(name, &command, &stopped);
50 if (ret < 0 && stopped) {
51 ERROR("'%s' is stopped", name);
52 return -1;
53 }
54
96fa1ff0
MN
55 if (ret < 0) {
56 ERROR("failed to send command");
57 return -1;
58 }
59
60 if (!ret) {
61 ERROR("console denied by '%s'", name);
62 return -1;
63 }
64
3cc5de36
MN
65 if (command.answer.ret) {
66 ERROR("console access denied: %s",
67 strerror(-command.answer.ret));
68 return -1;
69 }
70
96fa1ff0
MN
71 *fd = command.answer.fd;
72 if (*fd <0) {
73 ERROR("unable to allocate fd for tty %d", ttynum);
74 return -1;
75 }
76
77 INFO("tty %d allocated", ttynum);
78 return 0;
79}
724e753c
MN
80
81/*----------------------------------------------------------------------------
82 * functions used by lxc-start mainloop
83 * to handle above command request.
84 *--------------------------------------------------------------------------*/
85extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
86{
87 int i;
88
89 for (i = 0; i < tty_info->nbtty; i++) {
90
91 if (tty_info->pty_info[i].busy != fd)
92 continue;
93
94 tty_info->pty_info[i].busy = 0;
95 }
96
97 return;
98}
99
100extern int lxc_console_callback(int fd, struct lxc_request *request,
63376d7d 101 struct lxc_handler *handler)
724e753c
MN
102{
103 int ttynum = request->data;
fae349da 104 struct lxc_tty_info *tty_info = &handler->conf->tty_info;
724e753c
MN
105
106 if (ttynum > 0) {
107 if (ttynum > tty_info->nbtty)
108 goto out_close;
109
110 if (tty_info->pty_info[ttynum - 1].busy)
111 goto out_close;
112
113 goto out_send;
114 }
115
116 /* fixup index tty1 => [0] */
117 for (ttynum = 1;
118 ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
119 ttynum++);
120
121 /* we didn't find any available slot for tty */
122 if (ttynum > tty_info->nbtty)
123 goto out_close;
124
125out_send:
126 if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
127 &ttynum, sizeof(ttynum)) < 0) {
128 ERROR("failed to send tty to client");
129 goto out_close;
130 }
131
132 tty_info->pty_info[ttynum - 1].busy = fd;
133
134 return 0;
135
136out_close:
137 /* the close fd and related cleanup will be done by caller */
138 return 1;
139}
140
63376d7d
DL
141int lxc_create_console(struct lxc_console *console)
142{
143 if (openpty(&console->master, &console->slave,
144 console->name, NULL, NULL)) {
145 SYSERROR("failed to allocate a pty");
146 return -1;
147 }
148
149 if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
150 SYSERROR("failed to set console master to close-on-exec");
151 goto err;
152 }
153
154 if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
155 SYSERROR("failed to set console slave to close-on-exec");
156 goto err;
157 }
158
159 return 0;
160err:
161 close(console->master);
162 close(console->slave);
163 return -1;
164}
165
166void lxc_delete_console(const struct lxc_console *console)
167{
168 close(console->master);
169 close(console->slave);
170}
171
172static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
173{
174 struct lxc_console *console = (struct lxc_console *)data;
175 char buf[1024];
176 int r;
177
178 r = read(fd, buf, sizeof(buf));
179 if (r < 0) {
180 SYSERROR("failed to read");
181 return 1;
182 }
183
184 /* no output for the console, do nothing */
185 if (console->peer == -1)
186 return 0;
187
188 if (console->peer == fd)
189 write(console->master, buf, r);
190 else
191 write(console->peer, buf, r);
192
193 return 0;
194}
195
196int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
197 struct lxc_handler *handler)
198{
199 struct lxc_conf *conf = handler->conf;
200 struct lxc_console *console = &conf->console;
201
202 if (lxc_mainloop_add_handler(descr, console->master,
203 console_handler, console)) {
204 ERROR("failed to add to mainloop console handler for '%d'",
205 console->master);
206 return -1;
207 }
208
209 if (console->peer != -1 &&
210 lxc_mainloop_add_handler(descr, console->peer,
211 console_handler, console))
212 WARN("console input disabled");
213
214 return 0;
215}