]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_destroy.c
API: expose function lxc_log_init
[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
19712e04 20#define _GNU_SOURCE
446ca810 21#include "config.h"
60bf62d4 22
60bf62d4 23#include <libgen.h>
446ca810 24#include <stdio.h>
60bf62d4
SH
25#include <unistd.h>
26#include <sys/types.h>
27
446ca810
CB
28#include <lxc/lxccontainer.h>
29
60bf62d4 30#include "arguments.h"
446ca810
CB
31#include "log.h"
32#include "lxc.h"
60bf62d4
SH
33#include "utils.h"
34
6ea518f6 35lxc_log_define(lxc_destroy_ui, lxc);
60bf62d4 36
f29bb5d5 37static int my_parser(struct lxc_arguments* args, int c, char* arg);
2f0e6b79 38static bool quiet;
60bf62d4
SH
39
40static const struct option my_longopts[] = {
41 {"force", no_argument, 0, 'f'},
f29bb5d5 42 {"snapshots", no_argument, 0, 's'},
60bf62d4
SH
43 LXC_COMMON_OPTIONS
44};
45
46static struct lxc_arguments my_args = {
47 .progname = "lxc-destroy",
48 .help = "\
49--name=NAME [-f] [-P lxcpath]\n\
50\n\
4c1f6b67 51lxc-destroy destroys a container with the identifier NAME\n\
60bf62d4
SH
52\n\
53Options :\n\
f29bb5d5
CB
54 -n, --name=NAME NAME of the container\n\
55 -s, --snapshots destroy including all snapshots\n\
50b737a3
WB
56 -f, --force wait for the container to shut down\n\
57 --rcfile=FILE Load configuration file FILE\n",
60bf62d4
SH
58 .options = my_longopts,
59 .parser = my_parser,
60 .checker = NULL,
f29bb5d5 61 .task = DESTROY,
60bf62d4
SH
62};
63
2c5f2ede
CB
64static bool do_destroy(struct lxc_container *c);
65static bool do_destroy_with_snapshots(struct lxc_container *c);
f29bb5d5 66
60bf62d4
SH
67int main(int argc, char *argv[])
68{
69 struct lxc_container *c;
73b910a3 70 struct lxc_log log;
2c5f2ede 71 bool bret;
60bf62d4 72
60bf62d4 73 if (lxc_arguments_parse(&my_args, argc, argv))
f29bb5d5 74 exit(EXIT_FAILURE);
60bf62d4 75
f5abd74d
SG
76 if (!my_args.log_file)
77 my_args.log_file = "none";
78
73b910a3 79 log.name = my_args.name;
80 log.file = my_args.log_file;
81 log.priority = my_args.log_priority;
82 log.prefix = my_args.progname;
83 log.quiet = my_args.quiet;
84 log.lxcpath = my_args.lxcpath[0];
85
86 if (lxc_log_init(&log))
f29bb5d5 87 exit(EXIT_FAILURE);
6edbfc86 88 lxc_log_options_no_override();
2f0e6b79
SH
89 if (my_args.quiet)
90 quiet = true;
60bf62d4
SH
91
92 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
93 if (!c) {
2f0e6b79
SH
94 if (!quiet)
95 fprintf(stderr, "System error loading container\n");
f29bb5d5 96 exit(EXIT_FAILURE);
60bf62d4
SH
97 }
98
50b737a3
WB
99 if (my_args.rcfile) {
100 c->clear_config(c);
101 if (!c->load_config(c, my_args.rcfile)) {
102 fprintf(stderr, "Failed to load rcfile\n");
103 lxc_container_put(c);
104 exit(EXIT_FAILURE);
105 }
6118210e
WB
106 c->configfile = strdup(my_args.rcfile);
107 if (!c->configfile) {
108 fprintf(stderr, "Out of memory setting new config filename\n");
109 lxc_container_put(c);
110 exit(EXIT_FAILURE);
111 }
50b737a3
WB
112 }
113
f5abd74d 114 if (!c->may_control(c)) {
2f0e6b79
SH
115 if (!quiet)
116 fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
f3e52710 117 lxc_container_put(c);
f29bb5d5 118 exit(EXIT_FAILURE);
f5abd74d
SG
119 }
120
01e6b714 121 if (!c->is_defined(c)) {
2f0e6b79
SH
122 if (!quiet)
123 fprintf(stderr, "Container is not defined\n");
01e6b714 124 lxc_container_put(c);
f29bb5d5 125 exit(EXIT_FAILURE);
01e6b714
SH
126 }
127
f29bb5d5 128 if (my_args.task == SNAP) {
2c5f2ede
CB
129 bret = do_destroy_with_snapshots(c);
130 if (bret && !quiet)
131 printf("Destroyed container %s including snapshots \n", my_args.name);
f29bb5d5 132 } else {
2c5f2ede
CB
133 bret = do_destroy(c);
134 if (bret && !quiet)
135 printf("Destroyed container %s\n", my_args.name);
f29bb5d5
CB
136 }
137
138 lxc_container_put(c);
139
2c5f2ede 140 if (bret)
f29bb5d5
CB
141 exit(EXIT_SUCCESS);
142 exit(EXIT_FAILURE);
143}
144
145static int my_parser(struct lxc_arguments *args, int c, char *arg)
146{
147 switch (c) {
148 case 'f': args->force = 1; break;
149 case 's': args->task = SNAP; break;
150 }
151 return 0;
152}
153
2c5f2ede 154static bool do_destroy(struct lxc_container *c)
f29bb5d5 155{
2c5f2ede
CB
156 bool bret = true;
157 char path[MAXPATHLEN];
158
159 /* First check whether the container has dependent clones or snapshots. */
160 int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
161 if (ret < 0 || ret >= MAXPATHLEN)
162 return false;
163
164 if (file_exists(path)) {
2f0e6b79 165 if (!quiet)
2c5f2ede
CB
166 fprintf(stdout, "Destroying %s failed: %s has clones.\n", c->name, c->name);
167 return false;
7909bb03
CB
168 }
169
2c5f2ede
CB
170 ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
171 if (ret < 0 || ret >= MAXPATHLEN)
172 return false;
f29bb5d5 173
2c5f2ede
CB
174 if (dir_exists(path)) {
175 if (!quiet)
176 fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
177 return false;
178 }
179
180 if (c->is_running(c)) {
181 if (!my_args.force && !quiet) {
182 fprintf(stderr, "%s is running\n", my_args.name);
183 return false;
184 }
185 /* If the container was ephemeral it will be removed on shutdown. */
186 c->stop(c);
187 }
188
189 /* If the container was ephemeral we have already removed it when we
190 * stopped it. */
191 if (c->is_defined(c) && !c->lxc_conf->ephemeral)
192 bret = c->destroy(c);
193
194 if (!bret) {
195 if (!quiet)
196 fprintf(stderr, "Destroying %s failed\n", my_args.name);
197 return false;
198 }
199
200 return true;
7909bb03 201}
f29bb5d5 202
2c5f2ede 203static bool do_destroy_with_snapshots(struct lxc_container *c)
f29bb5d5 204{
19712e04
CB
205 struct lxc_container *c1;
206 struct stat fbuf;
4f64d0db 207 bool bret = false;
19712e04
CB
208 char path[MAXPATHLEN];
209 char *buf = NULL;
210 char *lxcpath = NULL;
211 char *lxcname = NULL;
212 char *scratch = NULL;
213 int fd;
214 int ret;
215 int counter = 0;
216
2c5f2ede 217 /* Destroy clones. */
19712e04 218 ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
793e387a 219 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede 220 return false;
19712e04
CB
221
222 fd = open(path, O_RDONLY | O_CLOEXEC);
c01859e8 223 if (fd >= 0) {
19712e04
CB
224 ret = fstat(fd, &fbuf);
225 if (ret < 0) {
226 close(fd);
2c5f2ede 227 return false;
19712e04
CB
228 }
229
230 /* Make sure that the string is \0 terminated. */
231 buf = calloc(fbuf.st_size + 1, sizeof(char));
232 if (!buf) {
233 SYSERROR("failed to allocate memory");
234 close(fd);
2c5f2ede 235 return false;
19712e04
CB
236 }
237
238 ret = read(fd, buf, fbuf.st_size);
239 if (ret < 0) {
240 ERROR("could not read %s", path);
241 close(fd);
242 free(buf);
2c5f2ede 243 return false;
19712e04
CB
244 }
245 close(fd);
246
247 while ((lxcpath = strtok_r(!counter ? buf : NULL, "\n", &scratch))) {
248 if (!(lxcname = strtok_r(NULL, "\n", &scratch)))
249 break;
250 c1 = lxc_container_new(lxcname, lxcpath);
4f64d0db
CB
251 if (!c1) {
252 counter++;
253 continue;
254 }
2c5f2ede
CB
255 /* We do not destroy recursively. If a clone of a clone
256 * has clones or snapshots the user should remove it
257 * explicitly. */
258 if (!do_destroy(c1)) {
19712e04
CB
259 lxc_container_put(c1);
260 free(buf);
2c5f2ede 261 return false;
19712e04
CB
262 }
263 lxc_container_put(c1);
264 counter++;
265 }
266 free(buf);
267 }
268
269 /* Destroy snapshots located in the containers snap/ folder. */
270 ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
271 if (ret < 0 || ret >= MAXPATHLEN)
2c5f2ede 272 return false;
4f64d0db
CB
273
274 if (dir_exists(path))
275 bret = c->destroy_with_snapshots(c);
276 else
2c5f2ede 277 bret = do_destroy(c);
4f64d0db 278
2c5f2ede 279 return bret;
f29bb5d5
CB
280}
281