~ubuntu-branches/ubuntu/quantal/lxc/quantal-201205292108

« back to all changes in this revision

Viewing changes to src/lxc/start.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter
  • Date: 2010-01-10 10:40:21 UTC
  • mto: (1.1.2 upstream) (3.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20100110104021-ff3ukvpu7yzc36hm
ImportĀ upstreamĀ versionĀ 0.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
#define PR_CAPBSET_DROP 24
89
89
#endif
90
90
 
 
91
#include <lxc/log.h>
 
92
#include <lxc/conf.h>
 
93
#include <lxc/confile.h>
 
94
#include <lxc/start.h>
 
95
#include <lxc/utils.h>
 
96
#include <lxc/cgroup.h>
 
97
#include <lxc/monitor.h>
 
98
 
91
99
#include "error.h"
92
100
#include "af_unix.h"
93
101
#include "mainloop.h"
 
102
#include "commands.h"
94
103
 
95
 
#include <lxc/lxc.h>
96
 
#include <lxc/log.h>
97
104
 
98
105
lxc_log_define(lxc_start, lxc);
99
106
 
100
107
LXC_TTY_HANDLER(SIGINT);
101
108
LXC_TTY_HANDLER(SIGQUIT);
102
109
 
103
 
struct lxc_handler {
104
 
        int sigfd;
105
 
        int lock;
106
 
        pid_t pid;
107
 
        char tty[MAXPATHLEN];
108
 
        sigset_t oldmask;
109
 
        struct lxc_tty_info tty_info;
110
 
};
111
 
 
112
110
static int setup_sigchld_fd(sigset_t *oldmask)
113
111
{
114
112
        sigset_t mask;
141
139
        return fd;
142
140
}
143
141
 
144
 
static int setup_tty_service(const char *name, int *ttyfd)
145
 
{
146
 
        int fd;
147
 
        struct sockaddr_un addr = { 0 };
148
 
        char *offset = &addr.sun_path[1];
149
 
        
150
 
        strcpy(offset, name);
151
 
        addr.sun_path[0] = '\0';
152
 
 
153
 
        fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
154
 
        if (fd < 0)
155
 
                return -1;
156
 
 
157
 
        if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
158
 
                SYSERROR("failed to close-on-exec flag");
159
 
                close(fd);
160
 
                return -1;
161
 
        }
162
 
 
163
 
        *ttyfd = fd;
164
 
 
165
 
        return 0;
166
 
}
167
 
 
168
142
static int sigchld_handler(int fd, void *data, 
169
143
                           struct lxc_epoll_descr *descr)
170
144
{
173
147
        return 1;
174
148
}
175
149
 
176
 
static int ttyclient_handler(int fd, void *data,
177
 
                             struct lxc_epoll_descr *descr)
 
150
int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
178
151
{
179
 
        int i;
180
 
        struct lxc_tty_info *tty_info = data;
181
 
 
182
 
        for (i = 0; i < tty_info->nbtty; i++) {
183
 
 
184
 
                if (tty_info->pty_info[i].busy != fd)
185
 
                        continue;
186
 
 
187
 
                lxc_mainloop_del_handler(descr, fd);
188
 
                tty_info->pty_info[i].busy = 0;
189
 
                close(fd);
190
 
        }
191
 
 
 
152
        handler->state = state;
 
153
        lxc_monitor_send_state(name, state);
192
154
        return 0;
193
155
}
194
156
 
195
 
static int ttyservice_handler(int fd, void *data,
196
 
                              struct lxc_epoll_descr *descr)
197
 
{
198
 
        int conn, ttynum, val = 1, ret = -1;
199
 
        struct lxc_tty_info *tty_info = data;
200
 
        
201
 
        conn = accept(fd, NULL, 0);
202
 
        if (conn < 0) {
203
 
                SYSERROR("failed to accept tty client");
204
 
                return -1;
205
 
        }
206
 
        
207
 
        if (setsockopt(conn, SOL_SOCKET, SO_PASSCRED, &val, sizeof(val))) {
208
 
                SYSERROR("failed to enable credential on socket");
209
 
                goto out_close;
210
 
        }
211
 
 
212
 
        if (lxc_af_unix_rcv_credential(conn, &ttynum, sizeof(ttynum)))
213
 
                goto out_close;
214
 
 
215
 
        if (ttynum > 0) {
216
 
                if (ttynum > tty_info->nbtty)
217
 
                        goto out_close;
218
 
 
219
 
                if (tty_info->pty_info[ttynum - 1].busy)
220
 
                        goto out_close;
221
 
 
222
 
                goto out_send;
223
 
        }
224
 
 
225
 
        /* fixup index tty1 => [0] */
226
 
        for (ttynum = 1;
227
 
             ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
228
 
             ttynum++);
229
 
 
230
 
        /* we didn't find any available slot for tty */
231
 
        if (ttynum > tty_info->nbtty)
232
 
                goto out_close;
233
 
 
234
 
out_send:
235
 
        if (lxc_af_unix_send_fd(conn, tty_info->pty_info[ttynum - 1].master,
236
 
                                &ttynum, sizeof(ttynum)) < 0) {
237
 
                ERROR("failed to send tty to client");
238
 
                goto out_close;
239
 
        }
240
 
 
241
 
        if (lxc_mainloop_add_handler(descr, conn,
242
 
                                     ttyclient_handler, tty_info)) {
243
 
                ERROR("failed to add tty client handler");
244
 
                goto out_close;
245
 
        }
246
 
 
247
 
        tty_info->pty_info[ttynum - 1].busy = conn;
248
 
 
249
 
        ret = 0;
250
 
out:
251
 
        return ret;
252
 
out_close:
253
 
        close(conn);
254
 
        goto out;
255
 
}
256
 
 
257
157
int lxc_poll(const char *name, struct lxc_handler *handler)
258
158
{
259
159
        int sigfd = handler->sigfd;
260
160
        int pid = handler->pid;
261
 
        const struct lxc_tty_info *tty_info = &handler->tty_info;
262
 
 
263
 
        int nfds, ttyfd = -1, ret = -1;
 
161
        int ret = -1;
264
162
        struct lxc_epoll_descr descr;
265
163
 
266
 
        if (tty_info->nbtty && setup_tty_service(name, &ttyfd)) {
267
 
                ERROR("failed to create the tty service point");
 
164
        if (lxc_mainloop_open(&descr)) {
 
165
                ERROR("failed to create mainloop");
268
166
                goto out_sigfd;
269
167
        }
270
168
 
271
 
        /* sigfd + nb tty + tty service 
272
 
         * if tty is enabled */
273
 
        nfds = tty_info->nbtty + 1 + tty_info->nbtty ? 1 : 0;
274
 
 
275
 
        if (lxc_mainloop_open(nfds, &descr)) {
276
 
                ERROR("failed to create mainloop");
277
 
                goto out_ttyfd;
278
 
        }
279
 
 
280
169
        if (lxc_mainloop_add_handler(&descr, sigfd, sigchld_handler, &pid)) {
281
170
                ERROR("failed to add handler for the signal");
282
171
                goto out_mainloop_open;
283
172
        }
284
173
 
285
 
        if (tty_info->nbtty) {
286
 
                if (lxc_mainloop_add_handler(&descr, ttyfd, 
287
 
                                             ttyservice_handler, 
288
 
                                             (void *)tty_info)) {
289
 
                        ERROR("failed to add handler for the tty");
290
 
                        goto out_mainloop_open;
291
 
                }
292
 
        }
 
174
        if (lxc_command_mainloop_add(name, &descr, handler))
 
175
                goto out_mainloop_open;
293
176
 
294
177
        ret = lxc_mainloop(&descr);
295
178
 
298
181
 
299
182
out_mainloop_open:
300
183
        lxc_mainloop_close(&descr);
301
 
out_ttyfd:
302
 
        close(ttyfd);
303
184
out_sigfd:
304
185
        close(sigfd);
305
186
        goto out;
306
187
}
307
188
 
308
 
static int save_init_pid(const char *name, pid_t pid)
309
 
{
310
 
        char init[MAXPATHLEN];
311
 
        char *val;
312
 
        int fd, err = -1;
313
 
 
314
 
        snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
315
 
 
316
 
        if (!asprintf(&val, "%d\n", pid)) {
317
 
                SYSERROR("failed to allocate memory");
318
 
                goto out;
319
 
        }
320
 
 
321
 
        fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
322
 
        if (fd < 0) {
323
 
                SYSERROR("failed to open '%s'", init);
324
 
                goto out_free;
325
 
        }
326
 
 
327
 
        if (write(fd, val, strlen(val)) < 0) {
328
 
                SYSERROR("failed to write the init pid");
329
 
                goto out_close;
330
 
        }
331
 
 
332
 
        err = 0;
333
 
 
334
 
out_close:
335
 
        close(fd);
336
 
out_free:
337
 
        free(val);
338
 
out:
339
 
        return err;
340
 
}
341
 
 
342
 
static void remove_init_pid(const char *name, pid_t pid)
343
 
{
344
 
        char init[MAXPATHLEN];
345
 
 
346
 
        snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
347
 
        unlink(init);
348
 
}
349
 
 
350
189
static int fdname(int fd, char *name, size_t size)
351
190
{
352
191
        char path[MAXPATHLEN];
391
230
        return 0;
392
231
}
393
232
 
394
 
struct lxc_handler *lxc_init(const char *name)
 
233
struct lxc_handler *lxc_init(const char *name, const char *rcfile)
395
234
{
396
235
        struct lxc_handler *handler;
397
236
 
401
240
 
402
241
        memset(handler, 0, sizeof(*handler));
403
242
 
404
 
        handler->lock = lxc_get_lock(name);
405
 
        if (handler->lock < 0)
406
 
                goto out_free;
407
 
 
408
243
        /* Begin the set the state to STARTING*/
409
 
        if (lxc_setstate(name, STARTING)) {
 
244
        if (lxc_set_state(name, handler, STARTING)) {
410
245
                ERROR("failed to set state '%s'", lxc_state2str(STARTING));
411
 
                goto out_put_lock;
412
 
        }
413
 
 
414
 
        if (console_init(handler->tty, sizeof(handler->tty))) {
 
246
                goto out_free;
 
247
        }
 
248
 
 
249
        if (lxc_conf_init(&handler->conf)) {
 
250
                ERROR("failed to initialize the configuration");
 
251
                goto out_aborting;
 
252
        }
 
253
 
 
254
        if (rcfile) {
 
255
                if (access(rcfile, F_OK)) {
 
256
                        ERROR("failed to access '%s'", rcfile);
 
257
                        goto out_aborting;
 
258
                }
 
259
 
 
260
                if (lxc_config_read(rcfile, &handler->conf)) {
 
261
                        ERROR("failed to read '%s'", rcfile);
 
262
                        goto out_aborting;
 
263
                }
 
264
        }
 
265
 
 
266
        if (console_init(handler->conf.console,
 
267
                         sizeof(handler->conf.console))) {
415
268
                ERROR("failed to initialize the console");
416
269
                goto out_aborting;
417
270
        }
418
271
 
419
 
        if (lxc_create_tty(name, &handler->tty_info)) {
 
272
        if (lxc_create_tty(name, &handler->conf)) {
420
273
                ERROR("failed to create the ttys");
421
274
                goto out_aborting;
422
275
        }
441
294
        return handler;
442
295
 
443
296
out_delete_tty:
444
 
        lxc_delete_tty(&handler->tty_info);
 
297
        lxc_delete_tty(&handler->conf.tty_info);
445
298
out_aborting:
446
 
        lxc_setstate(name, ABORTING);
447
 
out_put_lock:
448
 
        lxc_put_lock(handler->lock);
 
299
        lxc_set_state(name, handler, ABORTING);
449
300
out_free:
450
301
        free(handler);
451
302
        handler = NULL;
457
308
        /* The STOPPING state is there for future cleanup code
458
309
         * which can take awhile
459
310
         */
460
 
        lxc_setstate(name, STOPPING);
461
 
        lxc_setstate(name, STOPPED);
 
311
        lxc_set_state(name, handler, STOPPING);
 
312
        lxc_set_state(name, handler, STOPPED);
462
313
        lxc_unlink_nsgroup(name);
463
314
 
464
315
        if (handler) {
465
 
                remove_init_pid(name, handler->pid);
466
 
                lxc_delete_tty(&handler->tty_info);
467
 
                lxc_put_lock(handler->lock);
 
316
                lxc_delete_tty(&handler->conf.tty_info);
468
317
                free(handler);
469
318
        }
470
319
 
474
323
 
475
324
void lxc_abort(const char *name, struct lxc_handler *handler)
476
325
{
477
 
        lxc_setstate(name, ABORTING);
 
326
        lxc_set_state(name, handler, ABORTING);
478
327
        kill(handler->pid, SIGKILL);
479
328
}
480
329
 
517
366
        }
518
367
 
519
368
        /* Setup the container, ip, names, utsname, ... */
520
 
        if (lxc_setup(name, handler->tty, &handler->tty_info)) {
 
369
        if (lxc_setup(name, &handler->conf)) {
521
370
                ERROR("failed to setup the container");
522
371
                goto out_warn_father;
523
372
        }
527
376
                goto out_child;
528
377
        }
529
378
 
 
379
        if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
 
380
                SYSERROR("failed to set pdeath signal");
 
381
                goto out_child;
 
382
        }
 
383
 
530
384
        NOTICE("exec'ing '%s'", argv[0]);
531
385
 
532
386
        execvp(argv[0], argv);
560
414
        }
561
415
 
562
416
        clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
563
 
        if (conf_has_network(name))
 
417
        if (!lxc_list_empty(&handler->conf.network)) {
 
418
 
564
419
                clone_flags |= CLONE_NEWNET;
565
420
 
 
421
                /* that should be done before the clone because we will
 
422
                 * fill the netdev index and use them in the child
 
423
                 */
 
424
                if (lxc_create_network(&handler->conf.network)) {
 
425
                        ERROR("failed to create the network");
 
426
                        goto out_close;
 
427
                }
 
428
        }
 
429
 
566
430
        /* Create a process in a new set of namespaces */
567
431
        handler->pid = lxc_clone(do_start, &start_arg, clone_flags);
568
432
        if (handler->pid < 0) {
578
442
                goto out_abort;
579
443
        }
580
444
 
581
 
        if (lxc_rename_nsgroup(name, handler->pid) || lxc_link_nsgroup(name))
 
445
        if (lxc_rename_nsgroup(name, handler))
582
446
                goto out_abort;
583
447
 
584
448
        /* Create the network configuration */
585
 
        if (clone_flags & CLONE_NEWNET &&
586
 
            conf_create_network(name, handler->pid)) {
587
 
                ERROR("failed to create the configured network");
588
 
                goto out_abort;
 
449
        if (clone_flags & CLONE_NEWNET) {
 
450
                if (lxc_assign_network(&handler->conf.network, handler->pid)) {
 
451
                        ERROR("failed to create the configured network");
 
452
                        goto out_abort;
 
453
                }
589
454
        }
590
455
 
591
456
        /* Tell the child to continue its initialization */
600
465
                goto out_abort;
601
466
        }
602
467
 
603
 
        if (save_init_pid(name, handler->pid)) {
604
 
                ERROR("failed to save the init pid info");
605
 
                goto out_abort;
606
 
        }
607
 
 
608
 
        if (lxc_setstate(name, RUNNING)) {
 
468
        if (lxc_set_state(name, handler, RUNNING)) {
609
469
                ERROR("failed to set state to %s",
610
470
                              lxc_state2str(RUNNING));
611
471
                goto out_abort;
626
486
        goto out_close;
627
487
}
628
488
 
629
 
int lxc_start(const char *name, char *const argv[])
 
489
int lxc_start(const char *name, char *const argv[], const char *rcfile)
630
490
{
631
491
        struct lxc_handler *handler;
632
492
        int err = -1;
633
493
        int status;
634
494
 
635
 
        handler = lxc_init(name);
 
495
        handler = lxc_init(name, rcfile);
636
496
        if (!handler) {
637
497
                ERROR("failed to initialize the container");
638
 
                goto out;
 
498
                return -1;
639
499
        }
640
500
 
641
501
        err = lxc_spawn(name, handler, argv);