]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_destroy.c
tree-wide: fix includes to fix bionic builds
[mirror_lxc.git] / src / lxc / tools / lxc_destroy.c
CommitLineData
60bf62d4
SH
1/*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
d38dd64a
CB
20#ifndef _GNU_SOURCE
21#define _GNU_SOURCE 1
22#endif
e3347eef 23#include <fcntl.h>
60bf62d4 24#include <libgen.h>
446ca810 25#include <stdio.h>
e3347eef 26#include <string.h>
e3347eef 27#include <sys/stat.h>
60bf62d4 28#include <sys/types.h>
d38dd64a 29#include <unistd.h>
60bf62d4 30
446ca810
CB
31#include <lxc/lxccontainer.h>
32
60bf62d4 33#include "arguments.h"
d38dd64a 34#include "config.h"
75e607ba 35#include "log.h"
36#include "utils.h"
60bf62d4 37
75e607ba 38lxc_log_define(lxc_destroy, lxc);
39
40static int my_parser(struct lxc_arguments *args, int c, char *arg);
a5375956 41static bool do_destroy(struct lxc_container *c);
42static bool do_destroy_with_snapshots(struct lxc_container *c);
60bf62d4
SH
43
44static const struct option my_longopts[] = {
45 {"force", no_argument, 0, 'f'},
f29bb5d5 46 {"snapshots", no_argument, 0, 's'},
60bf62d4
SH
47 LXC_COMMON_OPTIONS
48};
49
50static struct lxc_arguments my_args = {
a5375956 51 .progname = "lxc-destroy",
52 .help = "\
60bf62d4
SH
53--name=NAME [-f] [-P lxcpath]\n\
54\n\
4c1f6b67 55lxc-destroy destroys a container with the identifier NAME\n\
60bf62d4
SH
56\n\
57Options :\n\
f29bb5d5
CB
58 -n, --name=NAME NAME of the container\n\
59 -s, --snapshots destroy including all snapshots\n\
50b737a3
WB
60 -f, --force wait for the container to shut down\n\
61 --rcfile=FILE Load configuration file FILE\n",
a5375956 62 .options = my_longopts,
63 .parser = my_parser,
64 .checker = NULL,
65 .log_priority = "ERROR",
66 .log_file = "none",
67 .task = DESTROY,
60bf62d4
SH
68};
69
f29bb5d5
CB
70static int my_parser(struct lxc_arguments *args, int c, char *arg)
71{
72 switch (c) {
a5375956 73 case 'f':
74 args->force = 1;
75 break;
76 case 's':
77 args->task = SNAP;
78 break;
f29bb5d5
CB
79 }
80 return 0;
81}
82
2c5f2ede 83static bool do_destroy(struct lxc_container *c)
f29bb5d5 84{
a5375956 85 int ret;
2c5f2ede 86 bool bret = true;
75e607ba 87 char path[MAXPATHLEN];
2c5f2ede
CB
88
89 /* First check whether the container has dependent clones or snapshots. */
a5375956 90 ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
75e607ba 91 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede
CB
92 return false;
93
94 if (file_exists(path)) {
8f0bdb05 95 ERROR("Destroying %s failed: %s has clones", c->name, c->name);
2c5f2ede 96 return false;
7909bb03
CB
97 }
98
75e607ba 99 ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
100 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede 101 return false;
f29bb5d5 102
eb0760f9 103 if (rmdir(path) < 0 && errno != ENOENT) {
8f0bdb05 104 ERROR("Destroying %s failed: %s has snapshots", c->name, c->name);
2c5f2ede
CB
105 return false;
106 }
107
108 if (c->is_running(c)) {
75e607ba 109 if (!my_args.force) {
110 ERROR("%s is running", my_args.name);
2c5f2ede
CB
111 return false;
112 }
75e607ba 113
2c5f2ede
CB
114 /* If the container was ephemeral it will be removed on shutdown. */
115 c->stop(c);
116 }
117
118 /* If the container was ephemeral we have already removed it when we
119 * stopped it. */
e3347eef
CB
120 if (c->is_defined(c)) {
121 char buf[256];
75e607ba 122
e3347eef 123 ret = c->get_config_item(c, "lxc.ephemeral", buf, 256);
a5375956 124 if (ret > 0 && strcmp(buf, "0") == 0)
e3347eef 125 bret = c->destroy(c);
e3347eef 126 }
2c5f2ede
CB
127
128 if (!bret) {
75e607ba 129 ERROR("Destroying %s failed", my_args.name);
2c5f2ede
CB
130 return false;
131 }
132
133 return true;
7909bb03 134}
f29bb5d5 135
2c5f2ede 136static bool do_destroy_with_snapshots(struct lxc_container *c)
f29bb5d5 137{
19712e04
CB
138 struct lxc_container *c1;
139 struct stat fbuf;
4f64d0db 140 bool bret = false;
75e607ba 141 char path[MAXPATHLEN];
19712e04
CB
142 char *buf = NULL;
143 char *lxcpath = NULL;
144 char *lxcname = NULL;
19712e04
CB
145 int fd;
146 int ret;
aeba3f80 147 ssize_t bytes;
19712e04 148
2c5f2ede 149 /* Destroy clones. */
75e607ba 150 ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
151 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede 152 return false;
19712e04
CB
153
154 fd = open(path, O_RDONLY | O_CLOEXEC);
c01859e8 155 if (fd >= 0) {
19712e04
CB
156 ret = fstat(fd, &fbuf);
157 if (ret < 0) {
158 close(fd);
2c5f2ede 159 return false;
19712e04
CB
160 }
161
162 /* Make sure that the string is \0 terminated. */
163 buf = calloc(fbuf.st_size + 1, sizeof(char));
164 if (!buf) {
75e607ba 165 ERROR("Failed to allocate memory");
19712e04 166 close(fd);
2c5f2ede 167 return false;
19712e04
CB
168 }
169
aeba3f80 170 bytes = lxc_read_nointr(fd, buf, fbuf.st_size);
7b6f89cd 171 close(fd);
aeba3f80 172 if (bytes != (ssize_t)fbuf.st_size) {
75e607ba 173 ERROR("Could not read %s", path);
19712e04 174 free(buf);
2c5f2ede 175 return false;
19712e04 176 }
19712e04 177
7de8e0a9 178 lxc_iterate_parts(lxcpath, buf, "\n") {
19712e04 179 c1 = lxc_container_new(lxcname, lxcpath);
7de8e0a9 180 if (!c1)
4f64d0db 181 continue;
75e607ba 182
2c5f2ede
CB
183 /* We do not destroy recursively. If a clone of a clone
184 * has clones or snapshots the user should remove it
185 * explicitly. */
186 if (!do_destroy(c1)) {
19712e04
CB
187 lxc_container_put(c1);
188 free(buf);
2c5f2ede 189 return false;
19712e04 190 }
75e607ba 191
19712e04 192 lxc_container_put(c1);
19712e04
CB
193 }
194 free(buf);
195 }
196
197 /* Destroy snapshots located in the containers snap/ folder. */
75e607ba 198 ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
199 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede 200 return false;
4f64d0db 201
eb0760f9 202 if (rmdir(path) < 0 && errno != ENOENT)
4f64d0db
CB
203 bret = c->destroy_with_snapshots(c);
204 else
2c5f2ede 205 bret = do_destroy(c);
4f64d0db 206
2c5f2ede 207 return bret;
f29bb5d5 208}
a5375956 209
210int main(int argc, char *argv[])
211{
212 struct lxc_container *c;
213 struct lxc_log log;
214 bool bret;
215
216 if (lxc_arguments_parse(&my_args, argc, argv))
217 exit(EXIT_FAILURE);
218
219 log.name = my_args.name;
220 log.file = my_args.log_file;
221 log.level = my_args.log_priority;
222 log.prefix = my_args.progname;
223 log.quiet = my_args.quiet;
224 log.lxcpath = my_args.lxcpath[0];
225
226 if (lxc_log_init(&log))
227 exit(EXIT_FAILURE);
228
229 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
230 if (!c) {
231 ERROR("System error loading container");
232 exit(EXIT_FAILURE);
233 }
234
235 if (my_args.rcfile) {
236 c->clear_config(c);
237
238 if (!c->load_config(c, my_args.rcfile)) {
239 ERROR("Failed to load rcfile");
240 lxc_container_put(c);
241 exit(EXIT_FAILURE);
242 }
243
244 c->configfile = strdup(my_args.rcfile);
245 if (!c->configfile) {
246 ERROR("Out of memory setting new config filename");
247 lxc_container_put(c);
248 exit(EXIT_FAILURE);
249 }
250 }
251
252 if (!c->may_control(c)) {
253 ERROR("Insufficent privileges to control %s", my_args.name);
254 lxc_container_put(c);
255 exit(EXIT_FAILURE);
256 }
257
258 if (!c->is_defined(c)) {
259 ERROR("Container is not defined");
260 lxc_container_put(c);
261 exit(EXIT_FAILURE);
262 }
263
264 if (my_args.task == SNAP) {
265 bret = do_destroy_with_snapshots(c);
266 if (bret)
267 ERROR("Destroyed container %s including snapshots", my_args.name);
268 } else {
269 bret = do_destroy(c);
270 if (bret)
271 ERROR("Destroyed container %s", my_args.name);
272 }
273
274 lxc_container_put(c);
275
276 if (bret)
277 exit(EXIT_SUCCESS);
278
279 exit(EXIT_FAILURE);
280}