]>
Commit | Line | Data |
---|---|---|
cc73685d | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
791e7a73 | 2 | |
d38dd64a CB |
3 | #ifndef _GNU_SOURCE |
4 | #define _GNU_SOURCE 1 | |
5 | #endif | |
7b40d70f | 6 | #include <errno.h> |
5e97c3fc | 7 | #include <libgen.h> |
ce4a1a11 CB |
8 | #include <stdio.h> |
9 | #include <stdlib.h> | |
5e97c3fc | 10 | #include <string.h> |
7b40d70f | 11 | #include <sys/param.h> |
ce4a1a11 CB |
12 | #include <sys/stat.h> |
13 | #include <sys/types.h> | |
0072887d | 14 | #include <sys/wait.h> |
d38dd64a | 15 | #include <unistd.h> |
5e97c3fc | 16 | |
12ae2a33 | 17 | #include "lxc.h" |
ce4a1a11 CB |
18 | |
19 | #include "arguments.h" | |
d899f11b | 20 | #include "caps.h" |
d38dd64a | 21 | #include "config.h" |
d899f11b | 22 | #include "confile.h" |
23 | #include "log.h" | |
24 | #include "utils.h" | |
25 | ||
26 | lxc_log_define(lxc_execute, lxc); | |
5e97c3fc | 27 | |
e8c0bb81 | 28 | static int my_parser(struct lxc_arguments *args, int c, char *arg); |
29 | static bool set_argv(struct lxc_container *c, struct lxc_arguments *args); | |
30 | ||
20117280 CLG |
31 | static struct lxc_list defines; |
32 | ||
e8c0bb81 | 33 | static const struct option my_longopts[] = { |
34 | {"daemon", no_argument, 0, 'd'}, | |
35 | {"rcfile", required_argument, 0, 'f'}, | |
36 | {"define", required_argument, 0, 's'}, | |
37 | {"uid", required_argument, 0, 'u'}, | |
38 | {"gid", required_argument, 0, 'g'}, | |
39 | {"share-net", required_argument, 0, OPT_SHARE_NET}, | |
40 | {"share-ipc", required_argument, 0, OPT_SHARE_IPC}, | |
41 | {"share-uts", required_argument, 0, OPT_SHARE_UTS}, | |
42 | {"share-pid", required_argument, 0, OPT_SHARE_PID}, | |
43 | LXC_COMMON_OPTIONS | |
44 | }; | |
45 | ||
46 | static struct lxc_arguments my_args = { | |
47 | .progname = "lxc-execute", | |
48 | .help = "\ | |
49 | --name=NAME -- COMMAND\n\ | |
50 | \n\ | |
51 | lxc-execute creates a container with the identifier NAME\n\ | |
52 | and execs COMMAND into this container.\n\ | |
53 | \n\ | |
54 | Options :\n\ | |
55 | -n, --name=NAME NAME of the container\n\ | |
56 | -d, --daemon Daemonize the container\n\ | |
57 | -f, --rcfile=FILE Load configuration file FILE\n\ | |
58 | -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ | |
59 | -u, --uid=UID Execute COMMAND with UID inside the container\n\ | |
60 | -g, --gid=GID Execute COMMAND with GID inside the container\n", | |
61 | .options = my_longopts, | |
62 | .parser = my_parser, | |
63 | .log_priority = "ERROR", | |
64 | .log_file = "none", | |
65 | .daemonize = 0, | |
cc94aaf3 CB |
66 | .uid = LXC_INVALID_UID, |
67 | .gid = LXC_INVALID_GID, | |
e8c0bb81 | 68 | }; |
69 | ||
d899f11b | 70 | static int my_parser(struct lxc_arguments *args, int c, char *arg) |
cda02a28 | 71 | { |
791e7a73 CB |
72 | int ret; |
73 | ||
cda02a28 | 74 | switch (c) { |
be442598 CB |
75 | case 'd': |
76 | args->daemonize = 1; | |
77 | break; | |
fb111ba0 CB |
78 | case 'f': |
79 | args->rcfile = arg; | |
80 | break; | |
81 | case 's': | |
791e7a73 CB |
82 | ret = lxc_config_define_add(&defines, arg); |
83 | if (ret < 0) | |
84 | lxc_config_define_free(&defines); | |
fb111ba0 CB |
85 | break; |
86 | case 'u': | |
87 | if (lxc_safe_uint(arg, &args->uid) < 0) | |
88 | return -1; | |
89 | break; | |
90 | case 'g': | |
91 | if (lxc_safe_uint(arg, &args->gid) < 0) | |
92 | return -1; | |
f4bdebfd CB |
93 | break; |
94 | case OPT_SHARE_NET: | |
95 | args->share_ns[LXC_NS_NET] = arg; | |
96 | break; | |
97 | case OPT_SHARE_IPC: | |
98 | args->share_ns[LXC_NS_IPC] = arg; | |
99 | break; | |
100 | case OPT_SHARE_UTS: | |
101 | args->share_ns[LXC_NS_UTS] = arg; | |
102 | break; | |
103 | case OPT_SHARE_PID: | |
104 | args->share_ns[LXC_NS_PID] = arg; | |
105 | break; | |
cda02a28 MN |
106 | } |
107 | return 0; | |
5e97c3fc | 108 | } |
109 | ||
791e7a73 | 110 | static bool set_argv(struct lxc_container *c, struct lxc_arguments *args) |
5cda27c1 | 111 | { |
791e7a73 | 112 | int ret; |
3a5996ff | 113 | char buf[PATH_MAX]; |
5cda27c1 SH |
114 | char **components, **p; |
115 | ||
0044aab0 | 116 | buf[0] = '\0'; |
3a5996ff | 117 | ret = c->get_config_item(c, "lxc.execute.cmd", buf, PATH_MAX); |
791e7a73 | 118 | if (ret < 0) |
5cda27c1 SH |
119 | return false; |
120 | ||
791e7a73 | 121 | components = lxc_string_split_quoted(buf); |
5cda27c1 SH |
122 | if (!components) |
123 | return false; | |
124 | ||
125 | args->argv = components; | |
e8c0bb81 | 126 | |
5cda27c1 SH |
127 | for (p = components; *p; p++) |
128 | args->argc++; | |
129 | ||
130 | return true; | |
131 | } | |
132 | ||
5e97c3fc | 133 | int main(int argc, char *argv[]) |
134 | { | |
aa460476 | 135 | struct lxc_container *c; |
73b910a3 | 136 | struct lxc_log log; |
020c90b7 | 137 | int err = EXIT_FAILURE; |
13bc2fd2 | 138 | int ret; |
aa460476 | 139 | bool bret; |
5e97c3fc | 140 | |
20117280 CLG |
141 | lxc_list_init(&defines); |
142 | ||
0ed9cc8b | 143 | if (lxc_caps_init()) |
020c90b7 | 144 | exit(err); |
0ed9cc8b | 145 | |
cda02a28 | 146 | if (lxc_arguments_parse(&my_args, argc, argv)) |
020c90b7 | 147 | exit(err); |
5e97c3fc | 148 | |
e8c0bb81 | 149 | log.name = my_args.name; |
150 | log.file = my_args.log_file; | |
151 | log.level = my_args.log_priority; | |
152 | log.prefix = my_args.progname; | |
153 | log.quiet = my_args.quiet; | |
154 | log.lxcpath = my_args.lxcpath[0]; | |
155 | ||
156 | if (lxc_log_init(&log)) | |
157 | exit(err); | |
5e97c3fc | 158 | |
aa460476 CB |
159 | c = lxc_container_new(my_args.name, my_args.lxcpath[0]); |
160 | if (!c) { | |
d899f11b | 161 | ERROR("Failed to create lxc_container"); |
020c90b7 | 162 | exit(err); |
aa460476 | 163 | } |
fa9ab205 | 164 | |
aa460476 CB |
165 | if (my_args.rcfile) { |
166 | c->clear_config(c); | |
d899f11b | 167 | |
aa460476 | 168 | if (!c->load_config(c, my_args.rcfile)) { |
d899f11b | 169 | ERROR("Failed to load rcfile"); |
020c90b7 | 170 | goto out; |
96c210bb | 171 | } |
d899f11b | 172 | |
aa460476 CB |
173 | c->configfile = strdup(my_args.rcfile); |
174 | if (!c->configfile) { | |
d899f11b | 175 | ERROR("Out of memory setting new config filename"); |
020c90b7 | 176 | goto out; |
96c210bb DL |
177 | } |
178 | } | |
179 | ||
19bfbf6e | 180 | if (!c->lxc_conf) { |
d899f11b | 181 | ERROR("Executing a container with no configuration file may crash the host"); |
020c90b7 | 182 | goto out; |
19bfbf6e CB |
183 | } |
184 | ||
e8c0bb81 | 185 | if (my_args.argc == 0) |
791e7a73 | 186 | if (!set_argv(c, &my_args)) { |
d899f11b | 187 | ERROR("Missing command to execute!"); |
020c90b7 | 188 | goto out; |
5cda27c1 | 189 | } |
5cda27c1 | 190 | |
e2eae703 | 191 | bret = lxc_config_define_load(&defines, c); |
020c90b7 FA |
192 | if (!bret) |
193 | goto out; | |
47d556f5 | 194 | |
cc94aaf3 | 195 | if (my_args.uid != LXC_INVALID_UID) { |
791e7a73 CB |
196 | char buf[256]; |
197 | ||
198 | ret = snprintf(buf, 256, "%d", my_args.uid); | |
020c90b7 FA |
199 | if (ret < 0 || (size_t)ret >= 256) |
200 | goto out; | |
791e7a73 | 201 | |
e2eae703 | 202 | bret = c->set_config_item(c, "lxc.init.uid", buf); |
020c90b7 FA |
203 | if (!bret) |
204 | goto out; | |
791e7a73 CB |
205 | } |
206 | ||
cc94aaf3 | 207 | if (my_args.gid != LXC_INVALID_GID) { |
791e7a73 | 208 | char buf[256]; |
c5cd20ce | 209 | |
791e7a73 | 210 | ret = snprintf(buf, 256, "%d", my_args.gid); |
020c90b7 FA |
211 | if (ret < 0 || (size_t)ret >= 256) |
212 | goto out; | |
791e7a73 | 213 | |
e2eae703 | 214 | bret = c->set_config_item(c, "lxc.init.gid", buf); |
020c90b7 FA |
215 | if (!bret) |
216 | goto out; | |
791e7a73 | 217 | } |
0d6b9aea | 218 | |
020c90b7 FA |
219 | if (!lxc_setup_shared_ns(&my_args, c)) |
220 | goto out; | |
4be48327 | 221 | |
be442598 | 222 | c->daemonize = my_args.daemonize == 1; |
d899f11b | 223 | |
aa460476 | 224 | bret = c->start(c, 1, my_args.argv); |
6de247e3 | 225 | if (!bret) { |
d899f11b | 226 | ERROR("Failed run an application inside container"); |
020c90b7 | 227 | goto out; |
6de247e3 | 228 | } |
d899f11b | 229 | |
020c90b7 FA |
230 | if (c->daemonize) { |
231 | err = EXIT_SUCCESS; | |
232 | } else { | |
e8c0bb81 | 233 | if (WIFEXITED(c->error_num)) |
020c90b7 | 234 | err = WEXITSTATUS(c->error_num); |
e8c0bb81 | 235 | else |
f9eff950 TA |
236 | /* Try to die with the same signal the task did. */ |
237 | kill(0, WTERMSIG(c->error_num)); | |
f9eff950 | 238 | } |
020c90b7 | 239 | |
020c90b7 FA |
240 | out: |
241 | lxc_container_put(c); | |
242 | exit(err); | |
5e97c3fc | 243 | } |