]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_init.c
tree-wide: priority -> level
[mirror_lxc.git] / src / lxc / tools / lxc_init.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <libgen.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <getopt.h>
35
36 #include "log.h"
37 #include "caps.h"
38 #include "error.h"
39 #include "initutils.h"
40 #include "lxccontainer.h"
41
42 lxc_log_define(lxc_init, lxc);
43
44 static int quiet;
45
46 static const struct option options[] = {
47 { "name", required_argument, NULL, 'n' },
48 { "logpriority", required_argument, NULL, 'l' },
49 { "quiet", no_argument, NULL, 'q' },
50 { "lxcpath", required_argument, NULL, 'P' },
51 { 0, 0, 0, 0 },
52 };
53
54 static sig_atomic_t was_interrupted = 0;
55
56 static void interrupt_handler(int sig)
57 {
58 if (!was_interrupted)
59 was_interrupted = sig;
60 }
61
62 static void usage(void) {
63 fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
64 "Common options :\n"
65 " -n, --name=NAME NAME of the container\n"
66 " -l, --logpriority=LEVEL Set log priority to LEVEL\n"
67 " -q, --quiet Don't produce any output\n"
68 " -P, --lxcpath=PATH Use specified container path\n"
69 " -?, --help Give this help list\n"
70 "\n"
71 "Mandatory or optional arguments to long options are also mandatory or optional\n"
72 "for any corresponding short options.\n"
73 "\n"
74 "NOTE: lxc-init is intended for use by lxc internally\n"
75 " and does not need to be run by hand\n\n");
76 }
77
78 int main(int argc, char *argv[])
79 {
80 pid_t pid;
81 int err;
82 char **aargv;
83 sigset_t mask, omask;
84 int i, have_status = 0, shutdown = 0;
85 int opt;
86 char *lxcpath = NULL, *name = NULL, *logpriority = NULL;
87 struct lxc_log log;
88
89 while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) {
90 switch(opt) {
91 case 'n':
92 name = optarg;
93 break;
94 case 'l':
95 logpriority = optarg;
96 break;
97 case 'q':
98 quiet = 1;
99 break;
100 case 'P':
101 lxcpath = optarg;
102 break;
103 default: /* '?' */
104 usage();
105 exit(EXIT_FAILURE);
106 }
107 }
108
109 log.name = name;
110 log.file = name ? NULL : "none";
111 log.level = logpriority;
112 log.prefix = basename(argv[0]);
113 log.quiet = quiet;
114 log.lxcpath = lxcpath;
115
116 err = lxc_log_init(&log);
117 if (err < 0)
118 exit(EXIT_FAILURE);
119 lxc_log_options_no_override();
120
121 if (!argv[optind]) {
122 ERROR("missing command to launch");
123 exit(EXIT_FAILURE);
124 }
125
126 aargv = &argv[optind];
127
128 /*
129 * mask all the signals so we are safe to install a
130 * signal handler and to fork
131 */
132 if (sigfillset(&mask) ||
133 sigdelset(&mask, SIGILL) ||
134 sigdelset(&mask, SIGSEGV) ||
135 sigdelset(&mask, SIGBUS) ||
136 sigprocmask(SIG_SETMASK, &mask, &omask)) {
137 SYSERROR("failed to set signal mask");
138 exit(EXIT_FAILURE);
139 }
140
141 for (i = 1; i < NSIG; i++) {
142 struct sigaction act;
143
144 /* Exclude some signals: ILL, SEGV and BUS are likely to
145 * reveal a bug and we want a core. STOP and KILL cannot be
146 * handled anyway: they're here for documentation.
147 */
148 if (i == SIGILL ||
149 i == SIGSEGV ||
150 i == SIGBUS ||
151 i == SIGSTOP ||
152 i == SIGKILL ||
153 i == 32 || i == 33)
154 continue;
155
156 if (sigfillset(&act.sa_mask) ||
157 sigdelset(&act.sa_mask, SIGILL) ||
158 sigdelset(&act.sa_mask, SIGSEGV) ||
159 sigdelset(&act.sa_mask, SIGBUS) ||
160 sigdelset(&act.sa_mask, SIGSTOP) ||
161 sigdelset(&act.sa_mask, SIGKILL)) {
162 ERROR("failed to set signal");
163 exit(EXIT_FAILURE);
164 }
165
166 act.sa_flags = 0;
167 act.sa_handler = interrupt_handler;
168 if (sigaction(i, &act, NULL) && errno != EINVAL) {
169 SYSERROR("failed to sigaction");
170 exit(EXIT_FAILURE);
171 }
172 }
173
174 lxc_setup_fs();
175
176 pid = fork();
177
178 if (pid < 0)
179 exit(EXIT_FAILURE);
180
181 if (!pid) {
182
183 /* restore default signal handlers */
184 for (i = 1; i < NSIG; i++)
185 signal(i, SIG_DFL);
186
187 if (sigprocmask(SIG_SETMASK, &omask, NULL)) {
188 SYSERROR("failed to set signal mask");
189 exit(EXIT_FAILURE);
190 }
191
192 NOTICE("about to exec '%s'", aargv[0]);
193
194 execvp(aargv[0], aargv);
195 ERROR("failed to exec: '%s' : %m", aargv[0]);
196 exit(err);
197 }
198
199 /* let's process the signals now */
200 if (sigdelset(&omask, SIGALRM) ||
201 sigprocmask(SIG_SETMASK, &omask, NULL)) {
202 SYSERROR("failed to set signal mask");
203 exit(EXIT_FAILURE);
204 }
205
206 /* no need of other inherited fds but stderr */
207 close(fileno(stdin));
208 close(fileno(stdout));
209
210 err = EXIT_SUCCESS;
211 for (;;) {
212 int status;
213 pid_t waited_pid;
214
215 switch (was_interrupted) {
216
217 case 0:
218 break;
219
220 case SIGPWR:
221 case SIGTERM:
222 if (!shutdown) {
223 shutdown = 1;
224 kill(-1, SIGTERM);
225 alarm(1);
226 }
227 break;
228
229 case SIGALRM:
230 kill(-1, SIGKILL);
231 break;
232
233 default:
234 kill(pid, was_interrupted);
235 break;
236 }
237
238 was_interrupted = 0;
239 waited_pid = wait(&status);
240 if (waited_pid < 0) {
241 if (errno == ECHILD)
242 goto out;
243 if (errno == EINTR)
244 continue;
245
246 ERROR("failed to wait child : %s",
247 strerror(errno));
248 goto out;
249 }
250
251 /* reset timer each time a process exited */
252 if (shutdown)
253 alarm(1);
254
255 /*
256 * keep the exit code of started application
257 * (not wrapped pid) and continue to wait for
258 * the end of the orphan group.
259 */
260 if (waited_pid == pid && !have_status) {
261 err = lxc_error_set_and_log(waited_pid, status);
262 have_status = 1;
263 }
264 }
265 out:
266 if (err < 0)
267 exit(EXIT_FAILURE);
268 exit(err);
269 }