Imported Upstream version 2.02.79
[platform/upstream/device-mapper.git] / lib / format_text / archiver.c
1 /*
2  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
7  * This copyrighted material is made available to anyone wishing to use,
8  * modify, copy, or redistribute it subject to the terms and conditions
9  * of the GNU Lesser General Public License v.2.1.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include "lib.h"
17 #include "archiver.h"
18 #include "format-text.h"
19 #include "lvm-file.h"
20 #include "lvm-string.h"
21 #include "lvmcache.h"
22 #include "toolcontext.h"
23 #include "locking.h"
24
25 #include <unistd.h>
26
27 struct archive_params {
28         int enabled;
29         char *dir;
30         unsigned int keep_days;
31         unsigned int keep_number;
32 };
33
34 struct backup_params {
35         int enabled;
36         char *dir;
37 };
38
39 int archive_init(struct cmd_context *cmd, const char *dir,
40                  unsigned int keep_days, unsigned int keep_min,
41                  int enabled)
42 {
43         archive_exit(cmd);
44
45         if (!(cmd->archive_params = dm_pool_zalloc(cmd->libmem,
46                                                 sizeof(*cmd->archive_params)))) {
47                 log_error("archive_params alloc failed");
48                 return 0;
49         }
50
51         cmd->archive_params->dir = NULL;
52
53         if (!*dir)
54                 return 1;
55
56         if (!(cmd->archive_params->dir = dm_strdup(dir))) {
57                 log_error("Couldn't copy archive directory name.");
58                 return 0;
59         }
60
61         cmd->archive_params->keep_days = keep_days;
62         cmd->archive_params->keep_number = keep_min;
63         archive_enable(cmd, enabled);
64
65         return 1;
66 }
67
68 void archive_exit(struct cmd_context *cmd)
69 {
70         if (!cmd->archive_params)
71                 return;
72         if (cmd->archive_params->dir)
73                 dm_free(cmd->archive_params->dir);
74         memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
75 }
76
77 void archive_enable(struct cmd_context *cmd, int flag)
78 {
79         cmd->archive_params->enabled = flag;
80 }
81
82 static char *_build_desc(struct dm_pool *mem, const char *line, int before)
83 {
84         size_t len = strlen(line) + 32;
85         char *buffer;
86
87         if (!(buffer = dm_pool_zalloc(mem, strlen(line) + 32)))
88                 return_NULL;
89
90         if (snprintf(buffer, len,
91                      "Created %s executing '%s'",
92                      before ? "*before*" : "*after*", line) < 0)
93                 return_NULL;
94
95         return buffer;
96 }
97
98 static int __archive(struct volume_group *vg)
99 {
100         char *desc;
101
102         if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1)))
103                 return_0;
104
105         return archive_vg(vg, vg->cmd->archive_params->dir, desc,
106                           vg->cmd->archive_params->keep_days,
107                           vg->cmd->archive_params->keep_number);
108 }
109
110 int archive(struct volume_group *vg)
111 {
112         if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
113                 return 1;
114
115         if (test_mode()) {
116                 log_verbose("Test mode: Skipping archiving of volume group.");
117                 return 1;
118         }
119
120         if (!dm_create_dir(vg->cmd->archive_params->dir))
121                 return 0;
122
123         /* Trap a read-only file system */
124         if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
125              (errno == EROFS))
126                 return 0;
127
128         log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
129                     vg->seqno);
130         if (!__archive(vg)) {
131                 log_error("Volume group \"%s\" metadata archive failed.",
132                           vg->name);
133                 return 0;
134         }
135
136         return 1;
137 }
138
139 int archive_display(struct cmd_context *cmd, const char *vg_name)
140 {
141         int r1, r2;
142
143         r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
144         r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
145
146         return r1 && r2;
147 }
148
149 int archive_display_file(struct cmd_context *cmd, const char *file)
150 {
151         int r;
152
153         r = archive_list_file(cmd, file);
154
155         return r;
156 }
157
158 int backup_init(struct cmd_context *cmd, const char *dir,
159                 int enabled)
160 {
161         backup_exit(cmd);
162
163         if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem,
164                                                sizeof(*cmd->backup_params)))) {
165                 log_error("backup_params alloc failed");
166                 return 0;
167         }
168
169         cmd->backup_params->dir = NULL;
170         if (!*dir)
171                 return 1;
172
173         if (!(cmd->backup_params->dir = dm_strdup(dir))) {
174                 log_error("Couldn't copy backup directory name.");
175                 return 0;
176         }
177         backup_enable(cmd, enabled);
178
179         return 1;
180 }
181
182 void backup_exit(struct cmd_context *cmd)
183 {
184         if (!cmd->backup_params)
185                 return;
186         if (cmd->backup_params->dir)
187                 dm_free(cmd->backup_params->dir);
188         memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
189 }
190
191 void backup_enable(struct cmd_context *cmd, int flag)
192 {
193         cmd->backup_params->enabled = flag;
194 }
195
196 static int __backup(struct volume_group *vg)
197 {
198         char name[PATH_MAX];
199         char *desc;
200
201         if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0)))
202                 return_0;
203
204         if (dm_snprintf(name, sizeof(name), "%s/%s",
205                          vg->cmd->backup_params->dir, vg->name) < 0) {
206                 log_error("Failed to generate volume group metadata backup "
207                           "filename.");
208                 return 0;
209         }
210
211         return backup_to_file(name, desc, vg);
212 }
213
214 int backup_locally(struct volume_group *vg)
215 {
216         if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
217                 log_warn("WARNING: This metadata update is NOT backed up");
218                 return 1;
219         }
220
221         if (test_mode()) {
222                 log_verbose("Test mode: Skipping volume group backup.");
223                 return 1;
224         }
225
226         if (!dm_create_dir(vg->cmd->backup_params->dir))
227                 return 0;
228
229         /* Trap a read-only file system */
230         if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
231             (errno == EROFS))
232                 return 0;
233
234         if (!__backup(vg)) {
235                 log_error("Backup of volume group %s metadata failed.",
236                           vg->name);
237                 return 0;
238         }
239
240         return 1;
241 }
242
243 int backup(struct volume_group *vg)
244 {
245         if (vg_is_clustered(vg))
246                 remote_backup_metadata(vg);
247
248         return backup_locally(vg);
249 }
250
251 int backup_remove(struct cmd_context *cmd, const char *vg_name)
252 {
253         char path[PATH_MAX];
254
255         if (dm_snprintf(path, sizeof(path), "%s/%s",
256                          cmd->backup_params->dir, vg_name) < 0) {
257                 log_error("Failed to generate backup filename (for removal).");
258                 return 0;
259         }
260
261         /*
262          * Let this fail silently.
263          */
264         unlink(path);
265         return 1;
266 }
267
268 struct volume_group *backup_read_vg(struct cmd_context *cmd,
269                                     const char *vg_name, const char *file)
270 {
271         struct volume_group *vg = NULL;
272         struct format_instance *tf;
273         struct metadata_area *mda;
274         void *context;
275
276         if (!(context = create_text_context(cmd, file,
277                                             cmd->cmd_line)) ||
278             !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
279                                                          NULL, context))) {
280                 log_error("Couldn't create text format object.");
281                 return NULL;
282         }
283
284         dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
285                 if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
286                         stack;
287                 break;
288         }
289
290         tf->fmt->ops->destroy_instance(tf);
291         return vg;
292 }
293
294 /* ORPHAN and VG locks held before calling this */
295 int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
296 {
297         struct pv_list *pvl;
298         struct physical_volume *pv;
299         struct lvmcache_info *info;
300
301         /*
302          * FIXME: Check that the PVs referenced in the backup are
303          * not members of other existing VGs.
304          */
305
306         /* Attempt to write out using currently active format */
307         if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
308                                                        NULL, NULL))) {
309                 log_error("Failed to allocate format instance");
310                 return 0;
311         }
312
313         /*
314          * Setting vg->old_name to a blank value will explicitly
315          * disable any attempt to check VG name in existing metadata.
316         */
317         vg->old_name = dm_pool_strdup(vg->vgmem, "");
318
319         /* Add any metadata areas on the PVs */
320         dm_list_iterate_items(pvl, &vg->pvs) {
321                 pv = pvl->pv;
322                 if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
323                         log_error("PV %s missing from cache",
324                                   pv_dev_name(pv));
325                         return 0;
326                 }
327                 if (cmd->fmt != info->fmt) {
328                         log_error("PV %s is a different format (seqno %s)",
329                                   pv_dev_name(pv), info->fmt->name);
330                         return 0;
331                 }
332                 if (!vg->fid->fmt->ops->
333                     pv_setup(vg->fid->fmt, UINT64_C(0), 0, 0, 0, 0, 0UL,
334                              UINT64_C(0), 0,
335                              &vg->fid->metadata_areas_in_use, pv, vg)) {
336                         log_error("Format-specific setup for %s failed",
337                                   pv_dev_name(pv));
338                         return 0;
339                 }
340         }
341
342         if (!vg_write(vg) || !vg_commit(vg))
343                 return_0;
344
345         return 1;
346 }
347
348 /* ORPHAN and VG locks held before calling this */
349 int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
350                              const char *file)
351 {
352         struct volume_group *vg;
353         int missing_pvs, r = 0;
354
355         /*
356          * Read in the volume group from the text file.
357          */
358         if (!(vg = backup_read_vg(cmd, vg_name, file)))
359                 return_0;
360
361         missing_pvs = vg_missing_pv_count(vg);
362         if (missing_pvs == 0)
363                 r = backup_restore_vg(cmd, vg);
364         else
365                 log_error("Cannot restore Volume Group %s with %i PVs "
366                           "marked as missing.", vg->name, missing_pvs);
367
368         free_vg(vg);
369         return r;
370 }
371
372 int backup_restore(struct cmd_context *cmd, const char *vg_name)
373 {
374         char path[PATH_MAX];
375
376         if (dm_snprintf(path, sizeof(path), "%s/%s",
377                          cmd->backup_params->dir, vg_name) < 0) {
378                 log_error("Failed to generate backup filename (for restore).");
379                 return 0;
380         }
381
382         return backup_restore_from_file(cmd, vg_name, path);
383 }
384
385 int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
386 {
387         int r = 0;
388         struct format_instance *tf;
389         struct metadata_area *mda;
390         void *context;
391         struct cmd_context *cmd;
392
393         cmd = vg->cmd;
394
395         log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
396
397         if (!(context = create_text_context(cmd, file, desc)) ||
398             !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
399                                                          NULL, context))) {
400                 log_error("Couldn't create backup object.");
401                 return 0;
402         }
403
404         if (!dm_list_size(&tf->metadata_areas_in_use)) {
405                 log_error(INTERNAL_ERROR "No in use metadata areas to write.");
406                 return 0;
407         }
408
409         /* Write and commit the metadata area */
410         dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
411                 if (!(r = mda->ops->vg_write(tf, vg, mda))) {
412                         stack;
413                         continue;
414                 }
415                 if (mda->ops->vg_commit &&
416                     !(r = mda->ops->vg_commit(tf, vg, mda))) {
417                         stack;
418                 }
419         }
420
421         tf->fmt->ops->destroy_instance(tf);
422         return r;
423 }
424
425 /*
426  * Update backup (and archive) if they're out-of-date or don't exist.
427  */
428 void check_current_backup(struct volume_group *vg)
429 {
430         char path[PATH_MAX];
431         struct volume_group *vg_backup;
432         int old_suppress;
433
434         if (vg_is_exported(vg))
435                 return;
436
437         if (dm_snprintf(path, sizeof(path), "%s/%s",
438                          vg->cmd->backup_params->dir, vg->name) < 0) {
439                 log_debug("Failed to generate backup filename.");
440                 return;
441         }
442
443         old_suppress = log_suppress(1);
444         /* Up-to-date backup exists? */
445         if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
446             (vg->seqno == vg_backup->seqno) &&
447             (id_equal(&vg->id, &vg_backup->id))) {
448                 log_suppress(old_suppress);
449                 free_vg(vg_backup);
450                 return;
451         }
452         log_suppress(old_suppress);
453
454         if (vg_backup) {
455                 archive(vg_backup);
456                 free_vg(vg_backup);
457         }
458         archive(vg);
459         backup_locally(vg);
460 }