]> git.proxmox.com Git - mirror_lxc.git/blame - src/liblxc/start.c
Initial revision
[mirror_lxc.git] / src / liblxc / start.c
CommitLineData
5e97c3fc 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 <string.h>
28#include <stdlib.h>
29#include <dirent.h>
30#include <errno.h>
31#include <unistd.h>
32#include <signal.h>
33#include <mntent.h>
34#include <sys/param.h>
35#include <sys/file.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <sys/prctl.h>
39#include <sys/wait.h>
40#include <netinet/in.h>
41#include <net/if.h>
42
43#include <lxc.h>
44#include <namespace.h>
45#include <network.h>
46#include <state.h>
47#include <cgroup.h>
48#include <utils.h>
49#include <list.h>
50#include <conf.h>
51#include <log.h>
52#include <lock.h>
53
54LXC_TTY_HANDLER(SIGINT);
55LXC_TTY_HANDLER(SIGQUIT);
56
57int lxc_start(const char *name, int argc, char *argv[],
58 lxc_callback_t prestart, void *data)
59{
60 char *init = NULL, *val = NULL;
61 int fd, lock, sv[2], sync = 0, err = -1;
62 pid_t pid;
63 int clone_flags;
64
65 lock = lxc_get_lock(name);
66 if (!lock) {
67 lxc_log_error("'%s' is busy", name);
68 return -1;
69 }
70
71 if (lock < 0) {
72 lxc_log_error("failed to acquire lock on '%s':%s",
73 name, strerror(-lock));
74 return -1;
75 }
76
77 fcntl(lock, F_SETFD, FD_CLOEXEC);
78
79 /* Begin the set the state to STARTING*/
80 if (lxc_setstate(name, STARTING)) {
81 lxc_log_error("failed to set state %s", state2str(STARTING));
82 goto out;
83 }
84
85 /* Synchro socketpair */
86 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
87 lxc_log_syserror("failed to create communication socketpair");
88 goto err;
89 }
90
91 /* Avoid signals from terminal */
92 LXC_TTY_ADD_HANDLER(SIGINT);
93 LXC_TTY_ADD_HANDLER(SIGQUIT);
94
95 clone_flags = CLONE_NEWPID|CLONE_NEWIPC;
96 if (conf_has_fstab(name))
97 clone_flags |= CLONE_NEWNS;
98 if (conf_has_utsname(name))
99 clone_flags |= CLONE_NEWUTS;
100 if (conf_has_network(name))
101 clone_flags |= CLONE_NEWNET;
102
103 /* Create a process in a new set of namespaces */
104 pid = fork_ns(clone_flags);
105 if (pid < 0) {
106 lxc_log_syserror("failed to fork into a new namespace");
107 goto err_fork_ns;
108 }
109
110 if (!pid) {
111
112 close(sv[1]);
113
114 /* Be sure we don't inherit this after the exec */
115 fcntl(sv[0], F_SETFD, FD_CLOEXEC);
116
117 /* Tell our father he can begin to configure the container */
118 if (write(sv[0], &sync, sizeof(sync)) < 0) {
119 lxc_log_syserror("failed to write socket");
120 return 1;
121 }
122
123 /* Wait for the father to finish the configuration */
124 if (read(sv[0], &sync, sizeof(sync)) < 0) {
125 lxc_log_syserror("failed to read socket");
126 return 1;
127 }
128
129 /* Setup the container, ip, names, utsname, ... */
130 if (lxc_setup(name)) {
131 lxc_log_error("failed to setup the container");
132 if (write(sv[0], &sync, sizeof(sync)) < 0)
133 lxc_log_syserror("failed to write the socket");
134 return -1;
135 }
136
137 /* If a callback has been passed, call it before doing exec */
138 if (prestart)
139 if (prestart(name, argc, argv, data)) {
140 lxc_log_error("prestart callback has failed");
141 return -1;
142 }
143
144 execvp(argv[0], argv);
145 lxc_log_syserror("failed to exec %s", argv[0]);
146
147 /* If the exec fails, tell that to our father */
148 if (write(sv[0], &sync, sizeof(sync)) < 0)
149 lxc_log_syserror("failed to write the socket");
150
151 return 1;
152 }
153
154 close(sv[0]);
155
156 /* Wait for the child to be ready */
157 if (read(sv[1], &sync, sizeof(sync)) < 0) {
158 lxc_log_syserror("failed to read the socket");
159 goto err_pipe_read;
160 }
161
162 /* Create the network configuration */
163 if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
164 lxc_log_error("failed to create the configured network");
165 goto err_create_network;
166 }
167
168 /* Tell the child to continue its initialization */
169 if (write(sv[1], &sync, sizeof(sync)) < 0) {
170 lxc_log_syserror("failed to write the socket");
171 goto err_pipe_write;
172 }
173
174 /* Wait for the child to exec or returning an error */
175 err = read(sv[1], &sync, sizeof(sync));
176 if (err < 0) {
177 lxc_log_error("failed to read the socket");
178 goto err_pipe_read2;
179 }
180
181 if (err > 0) {
182 lxc_log_error("something went wrong with %d", pid);
183 /* TODO : check status etc ... */
184 waitpid(pid, NULL, 0);
185 goto err_child_failed;
186 }
187
188 asprintf(&val, "%d\n", pid);
189 asprintf(&init, LXCPATH "/%s/init", name);
190 fd = open(init, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
191 if (fd < 0) {
192 lxc_log_syserror("failed to open '%s'", init);
193 goto err_write;
194 }
195
196 if (write(fd, val, strlen(val)) < 0) {
197 lxc_log_syserror("failed to write the init pid");
198 goto err_write;
199 }
200
201 close(fd);
202
203 if (lxc_link_nsgroup(name, pid))
204 lxc_log_warning("cgroupfs not found: cgroup disabled");
205
206 if (lxc_setstate(name, RUNNING)) {
207 lxc_log_error("failed to set state to %s", state2str(RUNNING));
208 goto err_state_failed;
209 }
210
211wait_again:
212 if (waitpid(pid, NULL, 0) < 0) {
213 if (errno == EINTR)
214 goto wait_again;
215 lxc_log_syserror("failed to wait the pid %d", pid);
216 goto err_waitpid_failed;
217 }
218
219 if (lxc_setstate(name, STOPPING))
220 lxc_log_error("failed to set state %s", state2str(STOPPING));
221
222 if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
223 lxc_log_error("failed to destroy the network");
224
225 err = 0;
226out:
227 if (lxc_setstate(name, STOPPED))
228 lxc_log_error("failed to set state %s", state2str(STOPPED));
229
230 lxc_unlink_nsgroup(name);
231 unlink(init);
232 free(init);
233 free(val);
234 lxc_put_lock(lock);
235
236 return err;
237
238err_write:
239 close(fd);
240
241err_state_failed:
242err_child_failed:
243err_pipe_read2:
244err_pipe_write:
245 if (clone_flags & CLONE_NEWNET)
246 conf_destroy_network(name);
247err_create_network:
248err_pipe_read:
249err_waitpid_failed:
250 if (lxc_setstate(name, ABORTING))
251 lxc_log_error("failed to set state %s", state2str(STOPPED));
252
253 kill(pid, SIGKILL);
254err_fork_ns:
255 LXC_TTY_DEL_HANDLER(SIGQUIT);
256 LXC_TTY_DEL_HANDLER(SIGINT);
257 close(sv[0]);
258 close(sv[1]);
259err:
260 goto out;
261}