]>
Commit | Line | Data |
---|---|---|
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 |
948955a2 | 21 | #include <lxc/lxccontainer.h> |
60bf62d4 SH |
22 | |
23 | #include <stdio.h> | |
24 | #include <libgen.h> | |
25 | #include <unistd.h> | |
26 | #include <sys/types.h> | |
27 | ||
f2363e38 ÇO |
28 | #include "lxc.h" |
29 | #include "log.h" | |
60bf62d4 SH |
30 | #include "arguments.h" |
31 | #include "utils.h" | |
32 | ||
6ea518f6 | 33 | lxc_log_define(lxc_destroy_ui, lxc); |
60bf62d4 | 34 | |
f29bb5d5 | 35 | static int my_parser(struct lxc_arguments* args, int c, char* arg); |
60bf62d4 SH |
36 | |
37 | static const struct option my_longopts[] = { | |
38 | {"force", no_argument, 0, 'f'}, | |
f29bb5d5 | 39 | {"snapshots", no_argument, 0, 's'}, |
60bf62d4 SH |
40 | LXC_COMMON_OPTIONS |
41 | }; | |
42 | ||
43 | static struct lxc_arguments my_args = { | |
44 | .progname = "lxc-destroy", | |
45 | .help = "\ | |
46 | --name=NAME [-f] [-P lxcpath]\n\ | |
47 | \n\ | |
4c1f6b67 | 48 | lxc-destroy destroys a container with the identifier NAME\n\ |
60bf62d4 SH |
49 | \n\ |
50 | Options :\n\ | |
f29bb5d5 CB |
51 | -n, --name=NAME NAME of the container\n\ |
52 | -s, --snapshots destroy including all snapshots\n\ | |
60bf62d4 SH |
53 | -f, --force wait for the container to shut down\n", |
54 | .options = my_longopts, | |
55 | .parser = my_parser, | |
56 | .checker = NULL, | |
f29bb5d5 | 57 | .task = DESTROY, |
60bf62d4 SH |
58 | }; |
59 | ||
f29bb5d5 CB |
60 | static int do_destroy(struct lxc_container *c); |
61 | static int do_destroy_with_snapshots(struct lxc_container *c); | |
62 | ||
60bf62d4 SH |
63 | int main(int argc, char *argv[]) |
64 | { | |
65 | struct lxc_container *c; | |
f29bb5d5 | 66 | int ret; |
60bf62d4 | 67 | |
60bf62d4 | 68 | if (lxc_arguments_parse(&my_args, argc, argv)) |
f29bb5d5 | 69 | exit(EXIT_FAILURE); |
60bf62d4 | 70 | |
f5abd74d SG |
71 | if (!my_args.log_file) |
72 | my_args.log_file = "none"; | |
73 | ||
60bf62d4 SH |
74 | if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority, |
75 | my_args.progname, my_args.quiet, my_args.lxcpath[0])) | |
f29bb5d5 | 76 | exit(EXIT_FAILURE); |
6edbfc86 | 77 | lxc_log_options_no_override(); |
60bf62d4 SH |
78 | |
79 | c = lxc_container_new(my_args.name, my_args.lxcpath[0]); | |
80 | if (!c) { | |
81 | fprintf(stderr, "System error loading container\n"); | |
f29bb5d5 | 82 | exit(EXIT_FAILURE); |
60bf62d4 SH |
83 | } |
84 | ||
f5abd74d SG |
85 | if (!c->may_control(c)) { |
86 | fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name); | |
f3e52710 | 87 | lxc_container_put(c); |
f29bb5d5 | 88 | exit(EXIT_FAILURE); |
f5abd74d SG |
89 | } |
90 | ||
01e6b714 SH |
91 | if (!c->is_defined(c)) { |
92 | fprintf(stderr, "Container is not defined\n"); | |
93 | lxc_container_put(c); | |
f29bb5d5 | 94 | exit(EXIT_FAILURE); |
01e6b714 SH |
95 | } |
96 | ||
60bf62d4 SH |
97 | if (c->is_running(c)) { |
98 | if (!my_args.force) { | |
99 | fprintf(stderr, "%s is running\n", my_args.name); | |
01e6b714 | 100 | lxc_container_put(c); |
f29bb5d5 | 101 | exit(EXIT_FAILURE); |
60bf62d4 SH |
102 | } |
103 | c->stop(c); | |
104 | } | |
105 | ||
f29bb5d5 CB |
106 | if (my_args.task == SNAP) { |
107 | ret = do_destroy_with_snapshots(c); | |
108 | } else { | |
109 | ret = do_destroy(c); | |
110 | } | |
111 | ||
112 | lxc_container_put(c); | |
113 | ||
114 | if (ret == 0) | |
115 | exit(EXIT_SUCCESS); | |
116 | exit(EXIT_FAILURE); | |
117 | } | |
118 | ||
119 | static int my_parser(struct lxc_arguments *args, int c, char *arg) | |
120 | { | |
121 | switch (c) { | |
122 | case 'f': args->force = 1; break; | |
123 | case 's': args->task = SNAP; break; | |
124 | } | |
125 | return 0; | |
126 | } | |
127 | ||
128 | static int do_destroy(struct lxc_container *c) | |
129 | { | |
93ea85c7 ÇO |
130 | if (!c->destroy(c)) { |
131 | fprintf(stderr, "Destroying %s failed\n", my_args.name); | |
f29bb5d5 | 132 | return -1; |
7909bb03 CB |
133 | } |
134 | ||
f29bb5d5 CB |
135 | printf("Destroyed container %s\n", my_args.name); |
136 | ||
137 | return 0; | |
7909bb03 | 138 | } |
f29bb5d5 CB |
139 | |
140 | static int do_destroy_with_snapshots(struct lxc_container *c) | |
141 | { | |
19712e04 CB |
142 | struct lxc_container *c1; |
143 | struct stat fbuf; | |
144 | char path[MAXPATHLEN]; | |
145 | char *buf = NULL; | |
146 | char *lxcpath = NULL; | |
147 | char *lxcname = NULL; | |
148 | char *scratch = NULL; | |
149 | int fd; | |
150 | int ret; | |
151 | int counter = 0; | |
152 | ||
153 | /* Destroy snapshots created with lxc-clone listed in lxc-snapshots. */ | |
154 | ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); | |
155 | ||
156 | fd = open(path, O_RDONLY | O_CLOEXEC); | |
c01859e8 | 157 | if (fd >= 0) { |
19712e04 CB |
158 | ret = fstat(fd, &fbuf); |
159 | if (ret < 0) { | |
160 | close(fd); | |
161 | return -1; | |
162 | } | |
163 | ||
164 | /* Make sure that the string is \0 terminated. */ | |
165 | buf = calloc(fbuf.st_size + 1, sizeof(char)); | |
166 | if (!buf) { | |
167 | SYSERROR("failed to allocate memory"); | |
168 | close(fd); | |
169 | free(buf); | |
170 | return -1; | |
171 | } | |
172 | ||
173 | ret = read(fd, buf, fbuf.st_size); | |
174 | if (ret < 0) { | |
175 | ERROR("could not read %s", path); | |
176 | close(fd); | |
177 | free(buf); | |
178 | return -1; | |
179 | } | |
180 | close(fd); | |
181 | ||
182 | while ((lxcpath = strtok_r(!counter ? buf : NULL, "\n", &scratch))) { | |
183 | if (!(lxcname = strtok_r(NULL, "\n", &scratch))) | |
184 | break; | |
185 | c1 = lxc_container_new(lxcname, lxcpath); | |
61111832 SH |
186 | if (!c1) |
187 | goto next; | |
19712e04 CB |
188 | if (!c1->destroy(c1)) { |
189 | fprintf(stderr, "Destroying snapshot %s of %s failed\n", lxcname, my_args.name); | |
190 | lxc_container_put(c1); | |
191 | free(buf); | |
192 | return -1; | |
193 | } | |
194 | lxc_container_put(c1); | |
61111832 | 195 | next: |
19712e04 CB |
196 | counter++; |
197 | } | |
198 | free(buf); | |
199 | } | |
200 | ||
201 | /* Destroy snapshots located in the containers snap/ folder. */ | |
202 | ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); | |
203 | if (ret < 0 || ret >= MAXPATHLEN) | |
f29bb5d5 | 204 | return -1; |
19712e04 CB |
205 | if (dir_exists(path)) { |
206 | if (!c->destroy_with_snapshots(c)) { | |
207 | fprintf(stderr, "Destroying %s failed\n", my_args.name); | |
208 | return -1; | |
209 | } | |
210 | } else { | |
211 | if (!c->destroy(c)) { | |
212 | fprintf(stderr, "Destroying %s failed\n", my_args.name); | |
213 | return -1; | |
214 | } | |
f29bb5d5 CB |
215 | } |
216 | ||
19712e04 | 217 | printf("Destroyed container %s including snapshots \n", my_args.name); |
f29bb5d5 CB |
218 | |
219 | return 0; | |
220 | } | |
221 |