~serge-hallyn/ubuntu/quantal/lxc/lxc-user-ns

« back to all changes in this revision

Viewing changes to .pc/lxc-use-user-namespace.patch/src/lxc/console.c

  • Committer: Serge Hallyn
  • Date: 2012-10-29 16:51:57 UTC
  • Revision ID: serge.hallyn@ubuntu.com-20121029165157-xw2nxym7eo0ocxu4
Add user namespaces patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <stdlib.h>
 
26
#include <unistd.h>
 
27
#include <fcntl.h>
 
28
#include <errno.h>
 
29
#include <pty.h>
 
30
#include <sys/types.h>
 
31
#include <sys/un.h>
 
32
 
 
33
#include "log.h"
 
34
#include "conf.h"
 
35
#include "start.h"      /* for struct lxc_handler */
 
36
#include "caps.h"
 
37
#include "commands.h"
 
38
#include "mainloop.h"
 
39
#include "af_unix.h"
 
40
 
 
41
lxc_log_define(lxc_console, lxc);
 
42
 
 
43
extern int lxc_console(const char *name, int ttynum, int *fd)
 
44
{
 
45
        int ret, stopped = 0;
 
46
        struct lxc_command command = {
 
47
                .request = { .type = LXC_COMMAND_TTY, .data = ttynum },
 
48
        };
 
49
 
 
50
        ret = lxc_command_connected(name, &command, &stopped);
 
51
        if (ret < 0 && stopped) {
 
52
                ERROR("'%s' is stopped", name);
 
53
                return -1;
 
54
        }
 
55
 
 
56
        if (ret < 0) {
 
57
                ERROR("failed to send command");
 
58
                return -1;
 
59
        }
 
60
 
 
61
        if (!ret) {
 
62
                ERROR("console denied by '%s'", name);
 
63
                return -1;
 
64
        }
 
65
 
 
66
        if (command.answer.ret) {
 
67
                ERROR("console access denied: %s",
 
68
                        strerror(-command.answer.ret));
 
69
                return -1;
 
70
        }
 
71
 
 
72
        *fd = command.answer.fd;
 
73
        if (*fd <0) {
 
74
                ERROR("unable to allocate fd for tty %d", ttynum);
 
75
                return -1;
 
76
        }
 
77
 
 
78
        INFO("tty %d allocated", ttynum);
 
79
        return 0;
 
80
}
 
81
 
 
82
/*----------------------------------------------------------------------------
 
83
 * functions used by lxc-start mainloop
 
84
 * to handle above command request.
 
85
 *--------------------------------------------------------------------------*/
 
86
extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
 
87
{
 
88
        int i;
 
89
 
 
90
        for (i = 0; i < tty_info->nbtty; i++) {
 
91
 
 
92
                if (tty_info->pty_info[i].busy != fd)
 
93
                        continue;
 
94
 
 
95
                tty_info->pty_info[i].busy = 0;
 
96
        }
 
97
 
 
98
        return;
 
99
}
 
100
 
 
101
extern int lxc_console_callback(int fd, struct lxc_request *request,
 
102
                                struct lxc_handler *handler)
 
103
{
 
104
        int ttynum = request->data;
 
105
        struct lxc_tty_info *tty_info = &handler->conf->tty_info;
 
106
 
 
107
        if (ttynum > 0) {
 
108
                if (ttynum > tty_info->nbtty)
 
109
                        goto out_close;
 
110
 
 
111
                if (tty_info->pty_info[ttynum - 1].busy)
 
112
                        goto out_close;
 
113
 
 
114
                goto out_send;
 
115
        }
 
116
 
 
117
        /* fixup index tty1 => [0] */
 
118
        for (ttynum = 1;
 
119
             ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
 
120
             ttynum++);
 
121
 
 
122
        /* we didn't find any available slot for tty */
 
123
        if (ttynum > tty_info->nbtty)
 
124
                goto out_close;
 
125
 
 
126
out_send:
 
127
        if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
 
128
                                &ttynum, sizeof(ttynum)) < 0) {
 
129
                ERROR("failed to send tty to client");
 
130
                goto out_close;
 
131
        }
 
132
 
 
133
        tty_info->pty_info[ttynum - 1].busy = fd;
 
134
 
 
135
        return 0;
 
136
 
 
137
out_close:
 
138
        /* the close fd and related cleanup will be done by caller */
 
139
        return 1;
 
140
}
 
141
 
 
142
static int get_default_console(char **console)
 
143
{
 
144
        int fd;
 
145
 
 
146
        if (!access("/dev/tty", F_OK)) {
 
147
                fd = open("/dev/tty", O_RDWR);
 
148
                if (fd > 0) {
 
149
                        close(fd);
 
150
                        *console = strdup("/dev/tty");
 
151
                        goto out;
 
152
                }
 
153
        }
 
154
 
 
155
        if (!access("/dev/null", F_OK)) {
 
156
                *console = strdup("/dev/null");
 
157
                goto out;
 
158
        }
 
159
 
 
160
        ERROR("No suitable default console");
 
161
out:
 
162
        return *console ? 0 : -1;
 
163
}
 
164
 
 
165
int lxc_create_console(struct lxc_conf *conf)
 
166
{
 
167
        struct termios tios;
 
168
        struct lxc_console *console = &conf->console;
 
169
        int fd;
 
170
 
 
171
        if (!conf->rootfs.path)
 
172
                return 0;
 
173
 
 
174
        if (!console->path && get_default_console(&console->path)) {
 
175
                ERROR("failed to get default console");
 
176
                return -1;
 
177
        }
 
178
 
 
179
        if (!strcmp(console->path, "none"))
 
180
                return 0;
 
181
 
 
182
        if (openpty(&console->master, &console->slave,
 
183
                    console->name, NULL, NULL)) {
 
184
                SYSERROR("failed to allocate a pty");
 
185
                return -1;
 
186
        }
 
187
 
 
188
        if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
 
189
                SYSERROR("failed to set console master to close-on-exec");
 
190
                goto err;
 
191
        }
 
192
 
 
193
        if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
 
194
                SYSERROR("failed to set console slave to close-on-exec");
 
195
                goto err;
 
196
        }
 
197
 
 
198
        fd = lxc_unpriv(open(console->path, O_CLOEXEC | O_RDWR | O_CREAT |
 
199
                             O_APPEND, 0600));
 
200
        if (fd < 0) {
 
201
                SYSERROR("failed to open '%s'", console->path);
 
202
                goto err;
 
203
        }
 
204
 
 
205
        DEBUG("using '%s' as console", console->path);
 
206
 
 
207
        console->peer = fd;
 
208
 
 
209
        if (!isatty(console->peer))
 
210
                return 0;
 
211
 
 
212
        console->tios = malloc(sizeof(tios));
 
213
        if (!console->tios) {
 
214
                SYSERROR("failed to allocate memory");
 
215
                goto err;
 
216
        }
 
217
 
 
218
        /* Get termios */
 
219
        if (tcgetattr(console->peer, console->tios)) {
 
220
                SYSERROR("failed to get current terminal settings");
 
221
                goto err_free;
 
222
        }
 
223
 
 
224
        tios = *console->tios;
 
225
 
 
226
        /* Remove the echo characters and signal reception, the echo
 
227
         * will be done below with master proxying */
 
228
        tios.c_iflag &= ~IGNBRK;
 
229
        tios.c_iflag &= BRKINT;
 
230
        tios.c_lflag &= ~(ECHO|ICANON|ISIG);
 
231
        tios.c_cc[VMIN] = 1;
 
232
        tios.c_cc[VTIME] = 0;
 
233
 
 
234
        /* Set new attributes */
 
235
        if (tcsetattr(console->peer, TCSAFLUSH, &tios)) {
 
236
                ERROR("failed to set new terminal settings");
 
237
                goto err_free;
 
238
        }
 
239
 
 
240
        return 0;
 
241
 
 
242
err_free:
 
243
        free(console->tios);
 
244
err:
 
245
        close(console->master);
 
246
        close(console->slave);
 
247
        return -1;
 
248
}
 
249
 
 
250
void lxc_delete_console(const struct lxc_console *console)
 
251
{
 
252
        if (console->tios &&
 
253
            tcsetattr(console->peer, TCSAFLUSH, console->tios))
 
254
                WARN("failed to set old terminal settings");
 
255
        close(console->master);
 
256
        close(console->slave);
 
257
}
 
258
 
 
259
static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
 
260
{
 
261
        struct lxc_console *console = (struct lxc_console *)data;
 
262
        char buf[1024];
 
263
        int r;
 
264
 
 
265
        r = read(fd, buf, sizeof(buf));
 
266
        if (r < 0) {
 
267
                SYSERROR("failed to read");
 
268
                return 1;
 
269
        }
 
270
 
 
271
        if (!r) {
 
272
                INFO("console client has exited");
 
273
                lxc_mainloop_del_handler(descr, fd);
 
274
                close(fd);
 
275
                return 0;
 
276
        }
 
277
 
 
278
        /* no output for the console, do nothing */
 
279
        if (console->peer == -1)
 
280
                return 0;
 
281
 
 
282
        if (console->peer == fd)
 
283
                r = write(console->master, buf, r);
 
284
        else
 
285
                r = write(console->peer, buf, r);
 
286
 
 
287
        return 0;
 
288
}
 
289
 
 
290
int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
 
291
                             struct lxc_handler *handler)
 
292
{
 
293
        struct lxc_conf *conf = handler->conf;
 
294
        struct lxc_console *console = &conf->console;
 
295
 
 
296
        if (!conf->rootfs.path) {
 
297
                INFO("no rootfs, no console.");
 
298
                return 0;
 
299
        }
 
300
 
 
301
        if (!console->path) {
 
302
                INFO("no console specified");
 
303
                return 0;
 
304
        }
 
305
 
 
306
        if (console->peer == -1) {
 
307
                INFO("no console will be used");
 
308
                return 0;
 
309
        }
 
310
 
 
311
        if (lxc_mainloop_add_handler(descr, console->master,
 
312
                                     console_handler, console)) {
 
313
                ERROR("failed to add to mainloop console handler for '%d'",
 
314
                      console->master);
 
315
                return -1;
 
316
        }
 
317
 
 
318
        if (console->peer != -1 &&
 
319
            lxc_mainloop_add_handler(descr, console->peer,
 
320
                                     console_handler, console))
 
321
                WARN("console input disabled");
 
322
 
 
323
        return 0;
 
324
}