]>
Commit | Line | Data |
---|---|---|
05f05512 | 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 <unistd.h> | |
26 | #include <stdlib.h> | |
27 | #include <errno.h> | |
b0a33c1e | 28 | #include <signal.h> |
8559e703 | 29 | #include <libgen.h> |
0e322d22 | 30 | #include <sys/stat.h> |
05f05512 | 31 | #include <sys/types.h> |
32 | #include <sys/wait.h> | |
05f05512 | 33 | #define _GNU_SOURCE |
34 | #include <getopt.h> | |
00b3c2e2 | 35 | |
05cda563 DL |
36 | #include "log.h" |
37 | #include "caps.h" | |
38 | #include "error.h" | |
698287d8 | 39 | #include "utils.h" |
8559e703 MN |
40 | |
41 | lxc_log_define(lxc_init, lxc); | |
05f05512 | 42 | |
8559e703 | 43 | static int quiet; |
05f05512 | 44 | |
45 | static struct option options[] = { | |
8559e703 MN |
46 | { "quiet", no_argument, &quiet, 1 }, |
47 | { 0, 0, 0, 0 }, | |
05f05512 | 48 | }; |
49 | ||
e4b3fe58 | 50 | static int was_interrupted = 0; |
51 | ||
05f05512 | 52 | int main(int argc, char *argv[]) |
53 | { | |
e4b3fe58 | 54 | |
55 | void interrupt_handler(int sig) | |
56 | { | |
57 | if (!was_interrupted) | |
58 | was_interrupted = sig; | |
59 | } | |
60 | ||
05f05512 | 61 | pid_t pid; |
05f05512 | 62 | int nbargs = 0; |
b0ed5e64 | 63 | int err = -1; |
05f05512 | 64 | char **aargv; |
e4b3fe58 | 65 | sigset_t mask, omask; |
6f0a4200 | 66 | int i, shutdown = 0; |
05f05512 | 67 | |
68 | while (1) { | |
69 | int ret = getopt_long_only(argc, argv, "", options, NULL); | |
8559e703 | 70 | if (ret == -1) { |
05f05512 | 71 | break; |
8559e703 | 72 | } |
341553f7 | 73 | if (ret == '?') |
b0ed5e64 | 74 | exit(err); |
341553f7 | 75 | |
05f05512 | 76 | nbargs++; |
77 | } | |
78 | ||
05cda563 DL |
79 | if (lxc_caps_init()) |
80 | exit(err); | |
81 | ||
341553f7 | 82 | if (lxc_log_init(NULL, 0, basename(argv[0]), quiet)) |
b0ed5e64 | 83 | exit(err); |
8559e703 | 84 | |
05f05512 | 85 | if (!argv[optind]) { |
8559e703 | 86 | ERROR("missing command to launch"); |
b0ed5e64 | 87 | exit(err); |
05f05512 | 88 | } |
89 | ||
90 | aargv = &argv[optind]; | |
91 | argc -= nbargs; | |
92 | ||
6f0a4200 DL |
93 | /* |
94 | * mask all the signals so we are safe to install a | |
95 | * signal handler and to fork | |
96 | */ | |
e4b3fe58 | 97 | sigfillset(&mask); |
5781a74a JX |
98 | sigdelset(&mask, SIGILL); |
99 | sigdelset(&mask, SIGSEGV); | |
100 | sigdelset(&mask, SIGBUS); | |
e4b3fe58 | 101 | sigprocmask(SIG_SETMASK, &mask, &omask); |
102 | ||
103 | for (i = 1; i < NSIG; i++) { | |
104 | struct sigaction act; | |
105 | ||
5781a74a JX |
106 | /* Exclude some signals: ILL, SEGV and BUS are likely to |
107 | * reveal a bug and we want a core. STOP and KILL cannot be | |
108 | * handled anyway: they're here for documentation. | |
109 | */ | |
110 | if (i == SIGILL || | |
111 | i == SIGSEGV || | |
112 | i == SIGBUS || | |
113 | i == SIGSTOP || | |
114 | i == SIGKILL) | |
115 | continue; | |
116 | ||
e4b3fe58 | 117 | sigfillset(&act.sa_mask); |
5781a74a JX |
118 | sigdelset(&act.sa_mask, SIGILL); |
119 | sigdelset(&act.sa_mask, SIGSEGV); | |
120 | sigdelset(&act.sa_mask, SIGBUS); | |
121 | sigdelset(&act.sa_mask, SIGSTOP); | |
122 | sigdelset(&act.sa_mask, SIGKILL); | |
e4b3fe58 | 123 | act.sa_flags = 0; |
124 | act.sa_handler = interrupt_handler; | |
125 | sigaction(i, &act, NULL); | |
126 | } | |
127 | ||
0af683cf | 128 | if (lxc_setup_fs()) |
129 | exit(err); | |
130 | ||
05cda563 | 131 | if (lxc_caps_reset()) |
0af683cf | 132 | exit(err); |
133 | ||
05f05512 | 134 | pid = fork(); |
c147356a | 135 | |
05f05512 | 136 | if (pid < 0) |
b0ed5e64 | 137 | exit(err); |
05f05512 | 138 | |
139 | if (!pid) { | |
c147356a | 140 | |
6f0a4200 | 141 | /* restore default signal handlers */ |
e4b3fe58 | 142 | for (i = 1; i < NSIG; i++) |
143 | signal(i, SIG_DFL); | |
6f0a4200 | 144 | |
e4b3fe58 | 145 | sigprocmask(SIG_SETMASK, &omask, NULL); |
146 | ||
72439b9f MN |
147 | NOTICE("about to exec '%s'", aargv[0]); |
148 | ||
05f05512 | 149 | execvp(aargv[0], aargv); |
0af683cf | 150 | ERROR("failed to exec: '%s' : %m", aargv[0]); |
b0ed5e64 | 151 | exit(err); |
05f05512 | 152 | } |
153 | ||
6f0a4200 DL |
154 | /* let's process the signals now */ |
155 | sigdelset(&omask, SIGALRM); | |
e4b3fe58 | 156 | sigprocmask(SIG_SETMASK, &omask, NULL); |
157 | ||
affaa6da MN |
158 | /* no need of other inherited fds but stderr */ |
159 | close(fileno(stdin)); | |
160 | close(fileno(stdout)); | |
161 | ||
37c3dfc9 | 162 | err = 0; |
05f05512 | 163 | for (;;) { |
164 | int status; | |
37c3dfc9 | 165 | int orphan = 0; |
b0ed5e64 MN |
166 | pid_t waited_pid; |
167 | ||
6fd1668e DL |
168 | switch (was_interrupted) { |
169 | ||
170 | case 0: | |
171 | break; | |
172 | ||
173 | case SIGTERM: | |
6f0a4200 DL |
174 | if (!shutdown) { |
175 | shutdown = 1; | |
176 | kill(-1, SIGTERM); | |
177 | alarm(1); | |
178 | } | |
179 | break; | |
180 | ||
181 | case SIGALRM: | |
182 | kill(-1, SIGKILL); | |
6fd1668e DL |
183 | break; |
184 | ||
185 | default: | |
e4b3fe58 | 186 | kill(pid, was_interrupted); |
6fd1668e | 187 | break; |
e4b3fe58 | 188 | } |
189 | ||
6fd1668e | 190 | was_interrupted = 0; |
b0ed5e64 MN |
191 | waited_pid = wait(&status); |
192 | if (waited_pid < 0) { | |
05f05512 | 193 | if (errno == ECHILD) |
b0ed5e64 | 194 | goto out; |
05f05512 | 195 | if (errno == EINTR) |
196 | continue; | |
6f0a4200 DL |
197 | |
198 | ERROR("failed to wait child : %s", | |
199 | strerror(errno)); | |
b0ed5e64 | 200 | goto out; |
05f05512 | 201 | } |
37c3dfc9 | 202 | |
6f0a4200 DL |
203 | /* reset timer each time a process exited */ |
204 | if (shutdown) | |
205 | alarm(1); | |
206 | ||
37c3dfc9 | 207 | /* |
6f0a4200 DL |
208 | * keep the exit code of started application |
209 | * (not wrapped pid) and continue to wait for | |
210 | * the end of the orphan group. | |
37c3dfc9 MN |
211 | */ |
212 | if ((waited_pid != pid) || (orphan ==1)) | |
213 | continue; | |
214 | orphan = 1; | |
215 | err = lxc_error_set_and_log(waited_pid, status); | |
05f05512 | 216 | } |
b0ed5e64 MN |
217 | out: |
218 | return err; | |
05f05512 | 219 | } |