Tizen 2.1 base
[external/device-mapper.git] / lib / format_text / export.c
1 /*
2  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2009 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 "import-export.h"
18 #include "metadata.h"
19 #include "display.h"
20 #include "lvm-string.h"
21 #include "segtype.h"
22 #include "text_export.h"
23 #include "lvm-version.h"
24
25 #include <stdarg.h>
26 #include <time.h>
27 #include <sys/utsname.h>
28
29 struct formatter;
30 typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
31                                     const char *fmt, va_list ap);
32 typedef int (*nl_fn) (struct formatter * f);
33
34 /*
35  * Macro for formatted output.
36  * out_with_comment_fn returns -1 if data didn't fit and buffer was expanded.
37  * Then argument list is reset and out_with_comment_fn is called again.
38  */
39 #define _out_with_comment(f, buffer, fmt, ap) \
40         do { \
41                 va_start(ap, fmt); \
42                 r = f->out_with_comment(f, buffer, fmt, ap); \
43                 va_end(ap); \
44         } while (r == -1)
45
46 /*
47  * The first half of this file deals with
48  * exporting the vg, ie. writing it to a file.
49  */
50 struct formatter {
51         struct dm_pool *mem;    /* pv names allocated from here */
52         struct dm_hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
53
54         union {
55                 FILE *fp;       /* where we're writing to */
56                 struct {
57                         char *start;
58                         uint32_t size;
59                         uint32_t used;
60                 } buf;
61         } data;
62
63         out_with_comment_fn out_with_comment;
64         nl_fn nl;
65
66         int indent;             /* current level of indentation */
67         int error;
68         int header;             /* 1 => comments at start; 0 => end */
69 };
70
71 static struct utsname _utsname;
72
73 static void _init(void)
74 {
75         static int _initialised = 0;
76
77         if (_initialised)
78                 return;
79
80         if (uname(&_utsname)) {
81                 log_error("uname failed: %s", strerror(errno));
82                 memset(&_utsname, 0, sizeof(_utsname));
83         }
84
85         _initialised = 1;
86 }
87
88 /*
89  * Formatting functions.
90  */
91
92 #define MAX_INDENT 5
93 static void _inc_indent(struct formatter *f)
94 {
95         if (++f->indent > MAX_INDENT)
96                 f->indent = MAX_INDENT;
97 }
98
99 static void _dec_indent(struct formatter *f)
100 {
101         if (!f->indent--) {
102                 log_error(INTERNAL_ERROR "problem tracking indentation");
103                 f->indent = 0;
104         }
105 }
106
107 /*
108  * Newline function for prettier layout.
109  */
110 static int _nl_file(struct formatter *f)
111 {
112         fprintf(f->data.fp, "\n");
113
114         return 1;
115 }
116
117 static int _extend_buffer(struct formatter *f)
118 {
119         char *newbuf;
120
121         log_debug("Doubling metadata output buffer to %" PRIu32,
122                   f->data.buf.size * 2);
123         if (!(newbuf = dm_realloc(f->data.buf.start,
124                                    f->data.buf.size * 2))) {
125                 log_error("Buffer reallocation failed.");
126                 return 0;
127         }
128         f->data.buf.start = newbuf;
129         f->data.buf.size *= 2;
130
131         return 1;
132 }
133
134 static int _nl_raw(struct formatter *f)
135 {
136         /* If metadata doesn't fit, extend buffer */
137         if ((f->data.buf.used + 2 > f->data.buf.size) &&
138             (!_extend_buffer(f)))
139                 return_0;
140
141         *(f->data.buf.start + f->data.buf.used) = '\n';
142         f->data.buf.used += 1;
143
144         *(f->data.buf.start + f->data.buf.used) = '\0';
145
146         return 1;
147 }
148
149 #define COMMENT_TAB 6
150 static int _out_with_comment_file(struct formatter *f, const char *comment,
151                                   const char *fmt, va_list ap)
152 {
153         int i;
154         char white_space[MAX_INDENT + 1];
155
156         if (ferror(f->data.fp))
157                 return 0;
158
159         for (i = 0; i < f->indent; i++)
160                 white_space[i] = '\t';
161         white_space[i] = '\0';
162         fputs(white_space, f->data.fp);
163         i = vfprintf(f->data.fp, fmt, ap);
164
165         if (comment) {
166                 /*
167                  * line comments up if possible.
168                  */
169                 i += 8 * f->indent;
170                 i /= 8;
171                 i++;
172
173                 do
174                         fputc('\t', f->data.fp);
175
176                 while (++i < COMMENT_TAB);
177
178                 fputs(comment, f->data.fp);
179         }
180         fputc('\n', f->data.fp);
181
182         return 1;
183 }
184
185 static int _out_with_comment_raw(struct formatter *f,
186                                  const char *comment __attribute__((unused)),
187                                  const char *fmt, va_list ap)
188 {
189         int n;
190
191         n = vsnprintf(f->data.buf.start + f->data.buf.used,
192                       f->data.buf.size - f->data.buf.used, fmt, ap);
193
194         /* If metadata doesn't fit, extend buffer */
195         if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
196                 if (!_extend_buffer(f))
197                         return_0;
198                 return -1; /* Retry */
199         }
200
201         f->data.buf.used += n;
202
203         outnl(f);
204
205         return 1;
206 }
207
208 /*
209  * Formats a string, converting a size specified
210  * in 512-byte sectors to a more human readable
211  * form (eg, megabytes).  We may want to lift this
212  * for other code to use.
213  */
214 static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
215 {
216         static const char *_units[] = {
217                 "Kilobytes",
218                 "Megabytes",
219                 "Gigabytes",
220                 "Terabytes",
221                 "Petabytes",
222                 "Exabytes",
223                 NULL
224         };
225
226         int i;
227         double d = (double) sectors;
228
229         /* to convert to K */
230         d /= 2.0;
231
232         for (i = 0; (d > 1024.0) && _units[i]; i++)
233                 d /= 1024.0;
234
235         return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
236 }
237
238 /* increment indention level */
239 void out_inc_indent(struct formatter *f)
240 {
241         _inc_indent(f);
242 }
243
244 /* decrement indention level */
245 void out_dec_indent(struct formatter *f)
246 {
247         _dec_indent(f);
248 }
249
250 /* insert new line */
251 int out_newline(struct formatter *f)
252 {
253         return f->nl(f);
254 }
255
256 /*
257  * Appends a comment giving a size in more easily
258  * readable form (eg, 4M instead of 8096).
259  */
260 int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
261 {
262         char buffer[64];
263         va_list ap;
264         int r;
265
266         if (!_sectors_to_units(size, buffer, sizeof(buffer)))
267                 return 0;
268
269         _out_with_comment(f, buffer, fmt, ap);
270
271         return r;
272 }
273
274 /*
275  * Appends a comment indicating that the line is
276  * only a hint.
277  */
278 int out_hint(struct formatter *f, const char *fmt, ...)
279 {
280         va_list ap;
281         int r;
282
283         _out_with_comment(f, "# Hint only", fmt, ap);
284
285         return r;
286 }
287
288 /*
289  * The normal output function with comment
290  */
291 int out_text_with_comment(struct formatter *f, const char *comment, const char *fmt, ...)
292 {
293         va_list ap;
294         int r;
295
296         _out_with_comment(f, comment, fmt, ap);
297
298         return r;
299 }
300
301 /*
302  * The normal output function.
303  */
304 int out_text(struct formatter *f, const char *fmt, ...)
305 {
306         va_list ap;
307         int r;
308
309         _out_with_comment(f, NULL, fmt, ap);
310
311         return r;
312 }
313
314 static int _out_line(const char *line, void *_f) {
315         struct formatter *f = (struct formatter *) _f;
316         return out_text(f, "%s", line);
317 }
318
319 int out_config_node(struct formatter *f, const struct config_node *cn)
320 {
321         return write_config_node(cn, _out_line, f);
322 }
323
324 static int _print_header(struct formatter *f,
325                          const char *desc)
326 {
327         char *buf;
328         time_t t;
329
330         t = time(NULL);
331
332         outf(f, "# Generated by LVM2 version %s: %s", LVM_VERSION, ctime(&t));
333         outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
334         outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
335         outnl(f);
336
337         if (!(buf = alloca(escaped_len(desc)))) {
338                 log_error("temporary stack allocation for description"
339                           "string failed");
340                 return 0;
341         }
342         outf(f, "description = \"%s\"", escape_double_quotes(buf, desc));
343         outnl(f);
344         outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
345              _utsname.sysname, _utsname.nodename, _utsname.release,
346              _utsname.version, _utsname.machine);
347         outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
348
349         return 1;
350 }
351
352 static int _print_flag_config(struct formatter *f, uint64_t status, int type)
353 {
354         char buffer[4096];
355         if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer)))
356                 return_0;
357         outf(f, "status = %s", buffer);
358
359         if (!print_flags(status, type, buffer, sizeof(buffer)))
360                 return_0;
361         outf(f, "flags = %s", buffer);
362
363         return 1;
364 }
365
366
367 static int _out_tags(struct formatter *f, struct dm_list *tags)
368 {
369         char *tag_buffer;
370
371         if (!dm_list_empty(tags)) {
372                 if (!(tag_buffer = alloc_printed_tags(tags)))
373                         return_0;
374                 if (!out_text(f, "tags = %s", tag_buffer)) {
375                         dm_free(tag_buffer);
376                         return_0;
377                 }
378                 dm_free(tag_buffer);
379         }
380
381         return 1;
382 }
383
384 static int _print_vg(struct formatter *f, struct volume_group *vg)
385 {
386         char buffer[4096];
387
388         if (!id_write_format(&vg->id, buffer, sizeof(buffer)))
389                 return_0;
390
391         outf(f, "id = \"%s\"", buffer);
392
393         outf(f, "seqno = %u", vg->seqno);
394
395         if (!_print_flag_config(f, vg->status, VG_FLAGS))
396                 return_0;
397
398         if (!_out_tags(f, &vg->tags))
399                 return_0;
400
401         if (vg->system_id && *vg->system_id)
402                 outf(f, "system_id = \"%s\"", vg->system_id);
403
404         outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
405                 vg->extent_size);
406         outf(f, "max_lv = %u", vg->max_lv);
407         outf(f, "max_pv = %u", vg->max_pv);
408
409         /* Default policy is NORMAL; INHERIT is meaningless */
410         if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
411                 outnl(f);
412                 outf(f, "allocation_policy = \"%s\"",
413                      get_alloc_string(vg->alloc));
414         }
415         outf(f, "metadata_copies = %u", vg->mda_copies);
416
417         return 1;
418 }
419
420 /*
421  * Get the pv%d name from the formatters hash
422  * table.
423  */
424 static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid)
425 {
426         return dm_hash_lookup(f->pv_names, uuid);
427 }
428
429 static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv)
430 {
431         char uuid[64] __attribute__((aligned(8)));
432
433         if (!pv || !id_write_format(&pv->id, uuid, sizeof(uuid)))
434                 return_NULL;
435
436         return _get_pv_name_from_uuid(f, uuid);
437 }
438
439 static int _print_pvs(struct formatter *f, struct volume_group *vg)
440 {
441         struct pv_list *pvl;
442         struct physical_volume *pv;
443         char buffer[4096];
444         char *buf;
445         const char *name;
446
447         outf(f, "physical_volumes {");
448         _inc_indent(f);
449
450         dm_list_iterate_items(pvl, &vg->pvs) {
451                 pv = pvl->pv;
452
453                 if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
454                         return_0;
455
456                 if (!(name = _get_pv_name_from_uuid(f, buffer)))
457                         return_0;
458
459                 outnl(f);
460                 outf(f, "%s {", name);
461                 _inc_indent(f);
462
463                 outf(f, "id = \"%s\"", buffer);
464
465                 if (!(buf = alloca(escaped_len(pv_dev_name(pv))))) {
466                         log_error("temporary stack allocation for device name"
467                                   "string failed");
468                         return 0;
469                 }
470
471                 outhint(f, "device = \"%s\"",
472                         escape_double_quotes(buf, pv_dev_name(pv)));
473                 outnl(f);
474
475                 if (!_print_flag_config(f, pv->status, PV_FLAGS))
476                         return_0;
477
478                 if (!_out_tags(f, &pv->tags))
479                         return_0;
480
481                 outsize(f, pv->size, "dev_size = %" PRIu64, pv->size);
482
483                 outf(f, "pe_start = %" PRIu64, pv->pe_start);
484                 outsize(f, vg->extent_size * (uint64_t) pv->pe_count,
485                         "pe_count = %u", pv->pe_count);
486
487                 _dec_indent(f);
488                 outf(f, "}");
489         }
490
491         _dec_indent(f);
492         outf(f, "}");
493         return 1;
494 }
495
496 static int _print_segment(struct formatter *f, struct volume_group *vg,
497                           int count, struct lv_segment *seg)
498 {
499         outf(f, "segment%u {", count);
500         _inc_indent(f);
501
502         outf(f, "start_extent = %u", seg->le);
503         outsize(f, (uint64_t) seg->len * vg->extent_size,
504                 "extent_count = %u", seg->len);
505
506         outnl(f);
507         outf(f, "type = \"%s\"", seg->segtype->name);
508
509         if (!_out_tags(f, &seg->tags))
510                 return_0;
511
512         if (seg->segtype->ops->text_export &&
513             !seg->segtype->ops->text_export(seg, f))
514                 return_0;
515
516         _dec_indent(f);
517         outf(f, "}");
518
519         return 1;
520 }
521
522 int out_areas(struct formatter *f, const struct lv_segment *seg,
523               const char *type)
524 {
525         const char *name;
526         unsigned int s;
527
528         outnl(f);
529
530         outf(f, "%ss = [", type);
531         _inc_indent(f);
532
533         for (s = 0; s < seg->area_count; s++) {
534                 switch (seg_type(seg, s)) {
535                 case AREA_PV:
536                         if (!(name = _get_pv_name(f, seg_pv(seg, s))))
537                                 return_0;
538
539                         outf(f, "\"%s\", %u%s", name,
540                              seg_pe(seg, s),
541                              (s == seg->area_count - 1) ? "" : ",");
542                         break;
543                 case AREA_LV:
544                         outf(f, "\"%s\", %u%s",
545                              seg_lv(seg, s)->name,
546                              seg_le(seg, s),
547                              (s == seg->area_count - 1) ? "" : ",");
548                         break;
549                 case AREA_UNASSIGNED:
550                         return 0;
551                 }
552         }
553
554         _dec_indent(f);
555         outf(f, "]");
556         return 1;
557 }
558
559 static int _print_lv(struct formatter *f, struct logical_volume *lv)
560 {
561         struct lv_segment *seg;
562         char buffer[4096];
563         int seg_count;
564
565         outnl(f);
566         outf(f, "%s {", lv->name);
567         _inc_indent(f);
568
569         /* FIXME: Write full lvid */
570         if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer)))
571                 return_0;
572
573         outf(f, "id = \"%s\"", buffer);
574
575         if (!_print_flag_config(f, lv->status, LV_FLAGS))
576                 return_0;
577
578         if (!_out_tags(f, &lv->tags))
579                 return_0;
580
581         if (lv->alloc != ALLOC_INHERIT)
582                 outf(f, "allocation_policy = \"%s\"",
583                      get_alloc_string(lv->alloc));
584
585         switch (lv->read_ahead) {
586         case DM_READ_AHEAD_NONE:
587                 outfc(f, "# None", "read_ahead = -1");
588                 break;
589         case DM_READ_AHEAD_AUTO:
590                 /* No output - use default */
591                 break;
592         default:
593                 outf(f, "read_ahead = %u", lv->read_ahead);
594         }
595
596         if (lv->major >= 0)
597                 outf(f, "major = %d", lv->major);
598         if (lv->minor >= 0)
599                 outf(f, "minor = %d", lv->minor);
600         outf(f, "segment_count = %u", dm_list_size(&lv->segments));
601         outnl(f);
602
603         seg_count = 1;
604         dm_list_iterate_items(seg, &lv->segments) {
605                 if (!_print_segment(f, lv->vg, seg_count++, seg))
606                         return_0;
607         }
608
609         _dec_indent(f);
610         outf(f, "}");
611
612         return 1;
613 }
614
615 static int _print_lvs(struct formatter *f, struct volume_group *vg)
616 {
617         struct lv_list *lvl;
618
619         /*
620          * Don't bother with an lv section if there are no lvs.
621          */
622         if (dm_list_empty(&vg->lvs))
623                 return 1;
624
625         outf(f, "logical_volumes {");
626         _inc_indent(f);
627
628         /*
629          * Write visible LVs first
630          */
631         dm_list_iterate_items(lvl, &vg->lvs) {
632                 if (!(lv_is_visible(lvl->lv)))
633                         continue;
634                 if (!_print_lv(f, lvl->lv))
635                         return_0;
636         }
637
638         dm_list_iterate_items(lvl, &vg->lvs) {
639                 if ((lv_is_visible(lvl->lv)))
640                         continue;
641                 if (!_print_lv(f, lvl->lv))
642                         return_0;
643         }
644
645         _dec_indent(f);
646         outf(f, "}");
647
648         return 1;
649 }
650
651 /*
652  * In the text format we refer to pv's as 'pv1',
653  * 'pv2' etc.  This function builds a hash table
654  * to enable a quick lookup from device -> name.
655  */
656 static int _build_pv_names(struct formatter *f, struct volume_group *vg)
657 {
658         int count = 0;
659         struct pv_list *pvl;
660         struct physical_volume *pv;
661         char buffer[32], *uuid, *name;
662
663         if (!(f->mem = dm_pool_create("text pv_names", 512)))
664                 return_0;
665
666         if (!(f->pv_names = dm_hash_create(128)))
667                 return_0;
668
669         dm_list_iterate_items(pvl, &vg->pvs) {
670                 pv = pvl->pv;
671
672                 /* FIXME But skip if there's already an LV called pv%d ! */
673                 if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
674                         return_0;
675
676                 if (!(name = dm_pool_strdup(f->mem, buffer)))
677                         return_0;
678
679                 if (!(uuid = dm_pool_zalloc(f->mem, 64)) ||
680                    !id_write_format(&pv->id, uuid, 64))
681                         return_0;
682
683                 if (!dm_hash_insert(f->pv_names, uuid, name))
684                         return_0;
685         }
686
687         return 1;
688 }
689
690 static int _text_vg_export(struct formatter *f,
691                            struct volume_group *vg, const char *desc)
692 {
693         int r = 0;
694
695         if (!_build_pv_names(f, vg))
696                 goto_out;
697
698         if (f->header && !_print_header(f, desc))
699                 goto_out;
700
701         if (!out_text(f, "%s {", vg->name))
702                 goto_out;
703
704         _inc_indent(f);
705
706         if (!_print_vg(f, vg))
707                 goto_out;
708
709         outnl(f);
710         if (!_print_pvs(f, vg))
711                 goto_out;
712
713         outnl(f);
714         if (!_print_lvs(f, vg))
715                 goto_out;
716
717         _dec_indent(f);
718         if (!out_text(f, "}"))
719                 goto_out;
720
721         if (!f->header && !_print_header(f, desc))
722                 goto_out;
723
724         r = 1;
725
726       out:
727         if (f->mem)
728                 dm_pool_destroy(f->mem);
729
730         if (f->pv_names)
731                 dm_hash_destroy(f->pv_names);
732
733         return r;
734 }
735
736 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
737 {
738         struct formatter *f;
739         int r;
740
741         _init();
742
743         if (!(f = dm_zalloc(sizeof(*f))))
744                 return_0;
745
746         f->data.fp = fp;
747         f->indent = 0;
748         f->header = 1;
749         f->out_with_comment = &_out_with_comment_file;
750         f->nl = &_nl_file;
751
752         r = _text_vg_export(f, vg, desc);
753         if (r)
754                 r = !ferror(f->data.fp);
755         dm_free(f);
756         return r;
757 }
758
759 /* Returns amount of buffer used incl. terminating NUL */
760 int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
761 {
762         struct formatter *f;
763         int r = 0;
764
765         _init();
766
767         if (!(f = dm_zalloc(sizeof(*f))))
768                 return_0;
769
770         f->data.buf.size = 65536;       /* Initial metadata limit */
771         if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) {
772                 log_error("text_export buffer allocation failed");
773                 goto out;
774         }
775
776         f->indent = 0;
777         f->header = 0;
778         f->out_with_comment = &_out_with_comment_raw;
779         f->nl = &_nl_raw;
780
781         if (!_text_vg_export(f, vg, desc)) {
782                 dm_free(f->data.buf.start);
783                 goto_out;
784         }
785
786         r = f->data.buf.used + 1;
787         *buf = f->data.buf.start;
788
789       out:
790         dm_free(f);
791         return r;
792 }
793
794 int export_vg_to_buffer(struct volume_group *vg, char **buf)
795 {
796         return text_vg_export_raw(vg, "", buf);
797 }
798
799 #undef outf
800 #undef outnl