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