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