]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_execute.c
tree-wide: fix lxc header inclusion
[mirror_lxc.git] / src / lxc / tools / lxc_execute.c
CommitLineData
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
26lxc_log_define(lxc_execute, lxc);
5e97c3fc 27
e8c0bb81 28static int my_parser(struct lxc_arguments *args, int c, char *arg);
29static bool set_argv(struct lxc_container *c, struct lxc_arguments *args);
30
20117280
CLG
31static struct lxc_list defines;
32
e8c0bb81 33static 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
46static struct lxc_arguments my_args = {
47 .progname = "lxc-execute",
48 .help = "\
49--name=NAME -- COMMAND\n\
50\n\
51lxc-execute creates a container with the identifier NAME\n\
52and execs COMMAND into this container.\n\
53\n\
54Options :\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 70static 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 110static 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 133int 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
240out:
241 lxc_container_put(c);
242 exit(err);
5e97c3fc 243}