~ubuntu-branches/ubuntu/quantal/lxc/quantal-201208301614

« back to all changes in this revision

Viewing changes to src/lxc/start.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter
  • Date: 2009-04-29 17:49:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090429174913-jvahs1ykizqtodje
Tags: upstream-0.6.2
ImportĀ upstreamĀ versionĀ 0.6.2

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 "../config.h"
 
25
#include <stdio.h>
 
26
#undef _GNU_SOURCE
 
27
#include <string.h>
 
28
#include <stdlib.h>
 
29
#include <dirent.h>
 
30
#include <errno.h>
 
31
#include <unistd.h>
 
32
#include <signal.h>
 
33
#include <fcntl.h>
 
34
#include <termios.h>
 
35
#include <sys/param.h>
 
36
#include <sys/file.h>
 
37
#include <sys/mount.h>
 
38
#include <sys/types.h>
 
39
#include <sys/prctl.h>
 
40
#include <sys/capability.h>
 
41
#include <sys/wait.h>
 
42
#include <sys/un.h>
 
43
#include <sys/poll.h>
 
44
 
 
45
#ifdef HAVE_SYS_SIGNALFD_H 
 
46
#  include <sys/signalfd.h>
 
47
#else
 
48
#  ifndef __NR_signalfd4
 
49
/* assume kernel headers are too old */
 
50
#    if __i386__
 
51
#      define __NR_signalfd4 327
 
52
#    elif __x86_64__
 
53
#      define __NR_signalfd4 289
 
54
#    elif __powerpc__
 
55
#      define __NR_signalfd4 313
 
56
#    elif __s390x__
 
57
#      define __NR_signalfd4 322
 
58
#    endif
 
59
#endif
 
60
 
 
61
#  ifndef __NR_signalfd
 
62
/* assume kernel headers are too old */
 
63
#    if __i386__
 
64
#      define __NR_signalfd 321
 
65
#    elif __x86_64__
 
66
#      define __NR_signalfd 282
 
67
#    elif __powerpc__
 
68
#      define __NR_signalfd 305
 
69
#    elif __s390x__
 
70
#      define __NR_signalfd 316
 
71
#    endif
 
72
#endif
 
73
 
 
74
int signalfd(int fd, const sigset_t *mask, int flags)
 
75
{
 
76
        int retval;
 
77
 
 
78
        retval = syscall (__NR_signalfd4, fd, mask, _NSIG / 8, flags);
 
79
        if (errno == ENOSYS && flags == 0)
 
80
                retval = syscall (__NR_signalfd, fd, mask, _NSIG / 8);
 
81
        return retval;
 
82
}
 
83
#endif
 
84
 
 
85
#if !HAVE_DECL_PR_CAPBSET_DROP
 
86
#define PR_CAPBSET_DROP 24
 
87
#endif
 
88
 
 
89
#include "error.h"
 
90
#include "af_unix.h"
 
91
#include "mainloop.h"
 
92
 
 
93
#include <lxc/lxc.h>
 
94
#include <lxc/log.h>
 
95
 
 
96
lxc_log_define(lxc_start, lxc);
 
97
 
 
98
 
 
99
LXC_TTY_HANDLER(SIGINT);
 
100
LXC_TTY_HANDLER(SIGQUIT);
 
101
 
 
102
static int setup_sigchld_fd(sigset_t *oldmask)
 
103
{
 
104
        sigset_t mask;
 
105
        int fd;
 
106
 
 
107
        if (sigprocmask(SIG_BLOCK, NULL, &mask)) {
 
108
                SYSERROR("failed to get mask signal");
 
109
                return -1;
 
110
        }
 
111
 
 
112
        if (sigaddset(&mask, SIGCHLD) || sigprocmask(SIG_BLOCK, &mask, oldmask)) {
 
113
                SYSERROR("failed to set mask signal");
 
114
                return -1;
 
115
        }
 
116
 
 
117
        fd = signalfd(-1, &mask, 0);
 
118
        if (fd < 0) {
 
119
                SYSERROR("failed to create the signal fd");
 
120
                return -1;
 
121
        }
 
122
 
 
123
        if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
 
124
                SYSERROR("failed to set sigfd to close-on-exec");
 
125
                close(fd);
 
126
                return -1;
 
127
        }
 
128
 
 
129
        return fd;
 
130
}
 
131
 
 
132
static int setup_tty_service(const char *name, int *ttyfd)
 
133
{
 
134
        int fd;
 
135
        struct sockaddr_un addr = { 0 };
 
136
        char *offset = &addr.sun_path[1];
 
137
        
 
138
        strcpy(offset, name);
 
139
        addr.sun_path[0] = '\0';
 
140
 
 
141
        fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
 
142
        if (fd < 0)
 
143
                return -1;
 
144
 
 
145
        if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
 
146
                SYSERROR("failed to close-on-exec flag");
 
147
                close(fd);
 
148
                return -1;
 
149
        }
 
150
 
 
151
        *ttyfd = fd;
 
152
 
 
153
        return 0;
 
154
}
 
155
 
 
156
static int sigchld_handler(int fd, void *data, 
 
157
                           struct lxc_epoll_descr *descr)
 
158
{
 
159
        pid_t *pid = data;
 
160
 
 
161
        waitpid(*pid, NULL, 0);
 
162
 
 
163
        return 1;
 
164
}
 
165
 
 
166
static int ttyclient_handler(int fd, void *data,
 
167
                             struct lxc_epoll_descr *descr)
 
168
{
 
169
        int i;
 
170
        struct lxc_tty_info *tty_info = data;
 
171
 
 
172
        for (i = 0; i < tty_info->nbtty; i++) {
 
173
 
 
174
                if (tty_info->pty_info[i].busy != fd)
 
175
                        continue;
 
176
 
 
177
                lxc_mainloop_del_handler(descr, fd);
 
178
                tty_info->pty_info[i].busy = 0;
 
179
                close(fd);
 
180
        }
 
181
 
 
182
        return 0;
 
183
}
 
184
 
 
185
static int ttyservice_handler(int fd, void *data,
 
186
                              struct lxc_epoll_descr *descr)
 
187
{
 
188
        int conn, ttynum, val = 1, ret = -1;
 
189
        struct lxc_tty_info *tty_info = data;
 
190
        
 
191
        conn = accept(fd, NULL, 0);
 
192
        if (conn < 0) {
 
193
                SYSERROR("failed to accept tty client");
 
194
                return -1;
 
195
        }
 
196
        
 
197
        if (setsockopt(conn, SOL_SOCKET, SO_PASSCRED, &val, sizeof(val))) {
 
198
                SYSERROR("failed to enable credential on socket");
 
199
                goto out_close;
 
200
        }
 
201
 
 
202
        if (lxc_af_unix_rcv_credential(conn, &ttynum, sizeof(ttynum)))
 
203
                goto out_close;
 
204
 
 
205
        if (ttynum <= 0 || ttynum > tty_info->nbtty)
 
206
                goto out_close;
 
207
 
 
208
        /* fixup index array (eg. tty1 is index 0) */
 
209
        ttynum--;
 
210
 
 
211
        if (tty_info->pty_info[ttynum].busy)
 
212
                goto out_close;
 
213
 
 
214
        if (lxc_af_unix_send_fd(conn, tty_info->pty_info[ttynum].master, 
 
215
                                NULL, 0) < 0) {
 
216
                ERROR("failed to send tty to client");
 
217
                goto out_close;
 
218
        }
 
219
 
 
220
        if (lxc_mainloop_add_handler(descr, conn, 
 
221
                                     ttyclient_handler, tty_info)) {
 
222
                ERROR("failed to add tty client handler");
 
223
                goto out_close;
 
224
        }
 
225
 
 
226
        tty_info->pty_info[ttynum].busy = conn;
 
227
 
 
228
        ret = 0;
 
229
 
 
230
out:
 
231
        return ret;
 
232
out_close:
 
233
        close(conn);
 
234
        goto out;
 
235
}
 
236
 
 
237
static int mainloop(const char *name, pid_t pid, int sigfd,
 
238
                    const struct lxc_tty_info *tty_info)
 
239
{
 
240
        int nfds, ttyfd = -1, ret = -1;
 
241
        struct lxc_epoll_descr descr;
 
242
 
 
243
        if (tty_info->nbtty && setup_tty_service(name, &ttyfd)) {
 
244
                ERROR("failed to create the tty service point");
 
245
                goto out_sigfd;
 
246
        }
 
247
 
 
248
        /* sigfd + nb tty + tty service 
 
249
         * if tty is enabled */
 
250
        nfds = tty_info->nbtty + 1 + tty_info->nbtty ? 1 : 0;
 
251
 
 
252
        if (lxc_mainloop_open(nfds, &descr)) {
 
253
                ERROR("failed to create mainloop");
 
254
                goto out_ttyfd;
 
255
        }
 
256
 
 
257
        if (lxc_mainloop_add_handler(&descr, sigfd, sigchld_handler, &pid)) {
 
258
                ERROR("failed to add handler for the signal");
 
259
                goto out_mainloop_open;
 
260
        }
 
261
 
 
262
        if (tty_info->nbtty) {
 
263
                if (lxc_mainloop_add_handler(&descr, ttyfd, 
 
264
                                             ttyservice_handler, 
 
265
                                             (void *)tty_info)) {
 
266
                        ERROR("failed to add handler for the tty");
 
267
                        goto out_mainloop_open;
 
268
                }
 
269
        }
 
270
 
 
271
        ret = lxc_mainloop(&descr);
 
272
 
 
273
out:
 
274
        return ret;
 
275
 
 
276
out_mainloop_open:
 
277
        lxc_mainloop_close(&descr);
 
278
out_ttyfd:
 
279
        close(ttyfd);
 
280
out_sigfd:
 
281
        close(sigfd);
 
282
        goto out;
 
283
}
 
284
 
 
285
int lxc_start(const char *name, char *argv[])
 
286
{
 
287
        struct lxc_tty_info tty_info = { 0 };
 
288
        sigset_t oldmask;
 
289
        char init[MAXPATHLEN];
 
290
        char tty[MAXPATHLEN];
 
291
        char *val = NULL;
 
292
        int fd, sigfd, lock, sv[2], sync = 0, err = -LXC_ERROR_INTERNAL;
 
293
        pid_t pid;
 
294
        int clone_flags;
 
295
 
 
296
        lock = lxc_get_lock(name);
 
297
        if (lock < 0)
 
298
                return lock;
 
299
 
 
300
        /* Begin the set the state to STARTING*/
 
301
        if (lxc_setstate(name, STARTING)) {
 
302
                ERROR("failed to set state '%s'",
 
303
                              lxc_state2str(STARTING));
 
304
                goto out;
 
305
        }
 
306
 
 
307
        /* If we are not attached to a tty, disable it */
 
308
        if (ttyname_r(0, tty, sizeof(tty))) 
 
309
                tty[0] = '\0';
 
310
 
 
311
        if (lxc_create_tty(name, &tty_info)) {
 
312
                ERROR("failed to create the ttys");
 
313
                goto out;
 
314
        }
 
315
 
 
316
        /* the signal fd has to be created before forking otherwise
 
317
         * if the child process exits before we setup the signal fd,
 
318
         * the event will be lost and the command will be stuck */
 
319
        sigfd = setup_sigchld_fd(&oldmask);
 
320
        if (sigfd < 0) {
 
321
                ERROR("failed to set sigchild fd handler");
 
322
                return -1;
 
323
        }
 
324
 
 
325
        /* Synchro socketpair */
 
326
        if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
 
327
                SYSERROR("failed to create communication socketpair");
 
328
                goto out;
 
329
        }
 
330
 
 
331
        /* Avoid signals from terminal */
 
332
        LXC_TTY_ADD_HANDLER(SIGINT);
 
333
        LXC_TTY_ADD_HANDLER(SIGQUIT);
 
334
 
 
335
        clone_flags = CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
 
336
        if (conf_has_utsname(name))
 
337
                clone_flags |= CLONE_NEWUTS;
 
338
        if (conf_has_network(name))
 
339
                clone_flags |= CLONE_NEWNET;
 
340
 
 
341
        /* Create a process in a new set of namespaces */
 
342
        pid = fork_ns(clone_flags);
 
343
        if (pid < 0) {
 
344
                SYSERROR("failed to fork into a new namespace");
 
345
                goto err_fork_ns;
 
346
        }
 
347
 
 
348
        if (!pid) {
 
349
 
 
350
                if (sigprocmask(SIG_SETMASK, &oldmask, NULL)) {
 
351
                        SYSERROR("failed to set sigprocmask");
 
352
                        return -1;
 
353
                }
 
354
 
 
355
                close(sv[1]);
 
356
 
 
357
                /* Be sure we don't inherit this after the exec */
 
358
                fcntl(sv[0], F_SETFD, FD_CLOEXEC);
 
359
                
 
360
                /* Tell our father he can begin to configure the container */
 
361
                if (write(sv[0], &sync, sizeof(sync)) < 0) {
 
362
                        SYSERROR("failed to write socket");
 
363
                        goto out_child;
 
364
                }
 
365
 
 
366
                /* Wait for the father to finish the configuration */
 
367
                if (read(sv[0], &sync, sizeof(sync)) < 0) {
 
368
                        SYSERROR("failed to read socket");
 
369
                        goto out_child;
 
370
                }
 
371
 
 
372
                /* Setup the container, ip, names, utsname, ... */
 
373
                err = lxc_setup(name, tty, &tty_info);
 
374
                if (err) {
 
375
                        ERROR("failed to setup the container");
 
376
                        if (write(sv[0], &err, sizeof(err)) < 0)
 
377
                                SYSERROR("failed to write the socket");
 
378
                        goto out_child;
 
379
                }
 
380
 
 
381
                if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
 
382
                        SYSERROR("failed to remove CAP_SYS_BOOT capability");
 
383
                        goto out_child;
 
384
                }
 
385
 
 
386
                execvp(argv[0], argv);
 
387
                SYSERROR("failed to exec %s", argv[0]);
 
388
 
 
389
                err = LXC_ERROR_WRONG_COMMAND;
 
390
                /* If the exec fails, tell that to our father */
 
391
                if (write(sv[0], &err, sizeof(err)) < 0)
 
392
                        SYSERROR("failed to write the socket");
 
393
                
 
394
        out_child:
 
395
                exit(err);
 
396
        }
 
397
 
 
398
        close(sv[0]);
 
399
        
 
400
        /* Wait for the child to be ready */
 
401
        if (read(sv[1], &sync, sizeof(sync)) < 0) {
 
402
                SYSERROR("failed to read the socket");
 
403
                goto err_pipe_read;
 
404
        }
 
405
 
 
406
        if (lxc_link_nsgroup(name, pid))
 
407
                WARN("cgroupfs not found: cgroup disabled");
 
408
 
 
409
        /* Create the network configuration */
 
410
        if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
 
411
                ERROR("failed to create the configured network");
 
412
                goto err_create_network;
 
413
        }
 
414
 
 
415
        /* Tell the child to continue its initialization */
 
416
        if (write(sv[1], &sync, sizeof(sync)) < 0) {
 
417
                SYSERROR("failed to write the socket");
 
418
                goto err_pipe_write;
 
419
        }
 
420
 
 
421
        /* Wait for the child to exec or returning an error */
 
422
        err = read(sv[1], &sync, sizeof(sync));
 
423
        if (err < 0) {
 
424
                ERROR("failed to read the socket");
 
425
                goto err_pipe_read2;
 
426
        }
 
427
 
 
428
        if (err > 0) {
 
429
                err = sync;
 
430
                waitpid(pid, NULL, 0);
 
431
                goto err_child_failed;
 
432
        }
 
433
 
 
434
        if (!asprintf(&val, "%d\n", pid)) {
 
435
                SYSERROR("failed to allocate memory");
 
436
                goto err_child_failed;
 
437
        }
 
438
 
 
439
        snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
 
440
 
 
441
        fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
 
442
        if (fd < 0) {
 
443
                SYSERROR("failed to open '%s'", init);
 
444
                goto err_write;
 
445
        }
 
446
        
 
447
        if (write(fd, val, strlen(val)) < 0) {
 
448
                SYSERROR("failed to write the init pid");
 
449
                goto err_write;
 
450
        }
 
451
 
 
452
        close(fd);
 
453
 
 
454
        if (lxc_setstate(name, RUNNING)) {
 
455
                ERROR("failed to set state to %s",
 
456
                              lxc_state2str(RUNNING));
 
457
                goto err_state_failed;
 
458
        }
 
459
 
 
460
        if (mainloop(name, pid, sigfd, &tty_info)) {
 
461
                ERROR("mainloop exited with an error");
 
462
                goto err_mailoop_failed;
 
463
        }
 
464
 
 
465
        if (lxc_setstate(name, STOPPING))
 
466
                ERROR("failed to set state %s", lxc_state2str(STOPPING));
 
467
 
 
468
        if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
 
469
                ERROR("failed to destroy the network");
 
470
 
 
471
        err = 0;
 
472
out:
 
473
        if (lxc_setstate(name, STOPPED))
 
474
                ERROR("failed to set state %s", lxc_state2str(STOPPED));
 
475
 
 
476
        lxc_delete_tty(&tty_info);
 
477
        lxc_unlink_nsgroup(name);
 
478
        unlink(init);
 
479
        free(val);
 
480
        lxc_put_lock(lock);
 
481
        LXC_TTY_DEL_HANDLER(SIGQUIT);
 
482
        LXC_TTY_DEL_HANDLER(SIGINT);
 
483
 
 
484
        return err;
 
485
 
 
486
err_write:
 
487
        close(fd);
 
488
 
 
489
err_state_failed:
 
490
err_child_failed:
 
491
err_pipe_read2:
 
492
err_pipe_write:
 
493
        if (clone_flags & CLONE_NEWNET)
 
494
                conf_destroy_network(name);
 
495
err_create_network:
 
496
err_pipe_read:
 
497
err_mailoop_failed:
 
498
        if (lxc_setstate(name, ABORTING))
 
499
                ERROR("failed to set state %s", lxc_state2str(STOPPED));
 
500
 
 
501
        kill(pid, SIGKILL);
 
502
err_fork_ns:
 
503
        close(sv[0]);
 
504
        close(sv[1]);
 
505
        goto out;
 
506
}