]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_snapshot.c
fd: only add valid fd to mainloop
[mirror_lxc.git] / src / lxc / tools / lxc_snapshot.c
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
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <libgen.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31
32 #include <lxc/lxccontainer.h>
33
34 #include "arguments.h"
35 #include "config.h"
36 #include "log.h"
37
38 lxc_log_define(lxc_snapshot, lxc);
39
40 static int my_parser(struct lxc_arguments *args, int c, char *arg);
41
42 static const struct option my_longopts[] = {
43 {"list", no_argument, 0, 'L'},
44 {"restore", required_argument, 0, 'r'},
45 {"newname", required_argument, 0, 'N'},
46 {"destroy", required_argument, 0, 'd'},
47 {"comment", required_argument, 0, 'c'},
48 {"showcomments", no_argument, 0, 'C'},
49 LXC_COMMON_OPTIONS
50 };
51
52 static struct lxc_arguments my_args = {
53 .progname = "lxc-snapshot",
54 .help = "\
55 --name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\
56 \n\
57 lxc-snapshot snapshots a container\n\
58 \n\
59 Options :\n\
60 -n, --name=NAME NAME of the container\n\
61 -L, --list list all snapshots\n\
62 -r, --restore=NAME restore snapshot NAME, e.g. 'snap0'\n\
63 -N, --newname=NEWNAME NEWNAME for the restored container\n\
64 -d, --destroy=NAME destroy snapshot NAME, e.g. 'snap0'\n\
65 use ALL to destroy all snapshots\n\
66 -c, --comment=FILE add FILE as a comment\n\
67 -C, --showcomments show snapshot comments\n\
68 --rcfile=FILE Load configuration file FILE\n",
69 .options = my_longopts,
70 .parser = my_parser,
71 .checker = NULL,
72 .task = SNAP,
73 };
74
75 static int do_snapshot(struct lxc_container *c, char *commentfile);
76 static int do_snapshot_destroy(struct lxc_container *c, char *snapname);
77 static int do_snapshot_list(struct lxc_container *c, int print_comments);
78 static int do_snapshot_restore(struct lxc_container *c,
79 struct lxc_arguments *args);
80 static int do_snapshot_task(struct lxc_container *c, enum task task);
81 static void print_file(char *path);
82
83 int main(int argc, char *argv[])
84 {
85 struct lxc_container *c;
86 struct lxc_log log;
87 int ret;
88
89 if (lxc_arguments_parse(&my_args, argc, argv))
90 exit(EXIT_FAILURE);
91
92 /* Only create log if explicitly instructed */
93 if (my_args.log_file || my_args.log_priority) {
94 log.name = my_args.name;
95 log.file = my_args.log_file;
96 log.level = my_args.log_priority;
97 log.prefix = my_args.progname;
98 log.quiet = my_args.quiet;
99 log.lxcpath = my_args.lxcpath[0];
100
101 if (lxc_log_init(&log))
102 exit(EXIT_FAILURE);
103 }
104
105 if (geteuid()) {
106 if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
107 ERROR("You lack access to %s", my_args.lxcpath[0]);
108 exit(EXIT_FAILURE);
109 }
110 }
111
112 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
113 if (!c) {
114 ERROR("System error loading container");
115 exit(EXIT_FAILURE);
116 }
117
118 if (my_args.rcfile) {
119 c->clear_config(c);
120
121 if (!c->load_config(c, my_args.rcfile)) {
122 ERROR("Failed to load rcfile");
123 lxc_container_put(c);
124 exit(EXIT_FAILURE);
125 }
126
127 c->configfile = strdup(my_args.rcfile);
128 if (!c->configfile) {
129 ERROR("Out of memory setting new config filename");
130 lxc_container_put(c);
131 exit(EXIT_FAILURE);
132 }
133 }
134
135 if (!c->lxc_conf) {
136 ERROR("No container config specified");
137 lxc_container_put(c);
138 exit(EXIT_FAILURE);
139 }
140
141 if (!c->may_control(c)) {
142 ERROR("Insufficent privileges to control %s", my_args.name);
143 lxc_container_put(c);
144 exit(EXIT_FAILURE);
145 }
146
147 ret = do_snapshot_task(c, my_args.task);
148
149 lxc_container_put(c);
150
151 if (ret == 0)
152 exit(EXIT_SUCCESS);
153
154 exit(EXIT_FAILURE);
155 }
156
157 static int do_snapshot_task(struct lxc_container *c, enum task task)
158 {
159 int ret = 0;
160
161 switch (task) {
162 case DESTROY:
163 ret = do_snapshot_destroy(c, my_args.snapname);
164 break;
165 case LIST:
166 ret = do_snapshot_list(c, my_args.print_comments);
167 break;
168 case RESTORE:
169 ret = do_snapshot_restore(c, &my_args);
170 break;
171 case SNAP:
172 ret = do_snapshot(c, my_args.commentfile);
173 break;
174 default:
175 ret = 0;
176 break;
177 }
178
179 return ret;
180 }
181
182 static int my_parser(struct lxc_arguments *args, int c, char *arg)
183 {
184 switch (c) {
185 case 'L':
186 args->task = LIST;
187 break;
188 case 'r':
189 args->task = RESTORE;
190 args->snapname = arg;
191 break;
192 case 'N':
193 args->newname = arg;
194 break;
195 case 'd':
196 args->task = DESTROY;
197 args->snapname = arg;
198 break;
199 case 'c':
200 args->commentfile = arg;
201 break;
202 case 'C':
203 args->print_comments = 1;
204 break;
205 }
206
207 return 0;
208 }
209
210 static int do_snapshot(struct lxc_container *c, char *commentfile)
211 {
212 int ret;
213
214 ret = c->snapshot(c, commentfile);
215 if (ret < 0) {
216 ERROR("Error creating a snapshot");
217 return -1;
218 }
219
220 return 0;
221 }
222
223 static int do_snapshot_destroy(struct lxc_container *c, char *snapname)
224 {
225 bool ret;
226
227 if (strncmp(snapname, "ALL", strlen(snapname)) == 0)
228 ret = c->snapshot_destroy_all(c);
229 else
230 ret = c->snapshot_destroy(c, snapname);
231
232 if (!ret) {
233 ERROR("Error destroying snapshot %s", snapname);
234 return -1;
235 }
236
237 return 0;
238 }
239
240 static int do_snapshot_list(struct lxc_container *c, int print_comments)
241 {
242 struct lxc_snapshot *s;
243 int i, n;
244
245 n = c->snapshot_list(c, &s);
246 if (n < 0) {
247 ERROR("Error listing snapshots");
248 return -1;
249 }
250
251 if (n == 0) {
252 printf("No snapshots\n");
253 return 0;
254 }
255
256 for (i = 0; i < n; i++) {
257 printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
258
259 if (print_comments)
260 print_file(s[i].comment_pathname);
261
262 s[i].free(&s[i]);
263 }
264
265 free(s);
266
267 return 0;
268 }
269
270 static int do_snapshot_restore(struct lxc_container *c,
271 struct lxc_arguments *args)
272 {
273 int bret;
274
275 /* When restoring a snapshot, the last optional argument if not given
276 * explicitly via the corresponding command line option is the name to
277 * use for the restored container. If no name is given, then the
278 * original container will be destroyed and the restored container will
279 * take its place. */
280 if ((!args->newname) && (args->argc > 1)) {
281 ERROR("Too many arguments");
282 return -1;
283 }
284
285 if ((!args->newname) && (args->argc == 1))
286 args->newname = args->argv[0];
287
288 bret = c->snapshot_restore(c, args->snapname, args->newname);
289 if (!bret) {
290 ERROR("Error restoring snapshot %s", args->snapname);
291 return -1;
292 }
293
294 return 0;
295 }
296
297 static void print_file(char *path)
298 {
299 FILE *f;
300 char *line = NULL;
301 size_t sz = 0;
302
303 if (!path)
304 return;
305
306 f = fopen(path, "r");
307 if (!f)
308 return;
309
310 while (getline(&line, &sz, f) != -1)
311 printf("%s", line);
312
313 free(line);
314 fclose(f);
315 }