Added Augeas support.
[libguestfs.git] / daemon / stubs.c
1 /* libguestfs generated file
2  * WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.
3  * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
4  *
5  * Copyright (C) 2009 Red Hat Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #define _GNU_SOURCE // for strchrnul
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <inttypes.h>
28 #include <ctype.h>
29 #include <rpc/types.h>
30 #include <rpc/xdr.h>
31
32 #include "daemon.h"
33 #include "../src/guestfs_protocol.h"
34 #include "actions.h"
35
36 static void mount_stub (XDR *xdr_in)
37 {
38   int r;
39   struct guestfs_mount_args args;
40   const char *device;
41   const char *mountpoint;
42
43   memset (&args, 0, sizeof args);
44
45   if (!xdr_guestfs_mount_args (xdr_in, &args)) {
46     reply_with_error ("%s: daemon failed to decode procedure arguments", "mount");
47     return;
48   }
49   device = args.device;
50   mountpoint = args.mountpoint;
51
52   r = do_mount (device, mountpoint);
53   if (r == -1)
54     /* do_mount has already called reply_with_error, so just return */
55     return;
56
57   reply (NULL, NULL);
58 }
59
60 static void sync_stub (XDR *xdr_in)
61 {
62   int r;
63
64   r = do_sync ();
65   if (r == -1)
66     /* do_sync has already called reply_with_error, so just return */
67     return;
68
69   reply (NULL, NULL);
70 }
71
72 static void touch_stub (XDR *xdr_in)
73 {
74   int r;
75   struct guestfs_touch_args args;
76   const char *path;
77
78   memset (&args, 0, sizeof args);
79
80   if (!xdr_guestfs_touch_args (xdr_in, &args)) {
81     reply_with_error ("%s: daemon failed to decode procedure arguments", "touch");
82     return;
83   }
84   path = args.path;
85
86   r = do_touch (path);
87   if (r == -1)
88     /* do_touch has already called reply_with_error, so just return */
89     return;
90
91   reply (NULL, NULL);
92 }
93
94 static void cat_stub (XDR *xdr_in)
95 {
96   char *r;
97   struct guestfs_cat_args args;
98   const char *path;
99
100   memset (&args, 0, sizeof args);
101
102   if (!xdr_guestfs_cat_args (xdr_in, &args)) {
103     reply_with_error ("%s: daemon failed to decode procedure arguments", "cat");
104     return;
105   }
106   path = args.path;
107
108   r = do_cat (path);
109   if (r == NULL)
110     /* do_cat has already called reply_with_error, so just return */
111     return;
112
113   struct guestfs_cat_ret ret;
114   ret.content = r;
115   reply ((xdrproc_t) &xdr_guestfs_cat_ret, (char *) &ret);
116   free (r);
117 }
118
119 static void ll_stub (XDR *xdr_in)
120 {
121   char *r;
122   struct guestfs_ll_args args;
123   const char *directory;
124
125   memset (&args, 0, sizeof args);
126
127   if (!xdr_guestfs_ll_args (xdr_in, &args)) {
128     reply_with_error ("%s: daemon failed to decode procedure arguments", "ll");
129     return;
130   }
131   directory = args.directory;
132
133   r = do_ll (directory);
134   if (r == NULL)
135     /* do_ll has already called reply_with_error, so just return */
136     return;
137
138   struct guestfs_ll_ret ret;
139   ret.listing = r;
140   reply ((xdrproc_t) &xdr_guestfs_ll_ret, (char *) &ret);
141   free (r);
142 }
143
144 static void ls_stub (XDR *xdr_in)
145 {
146   char **r;
147   struct guestfs_ls_args args;
148   const char *directory;
149
150   memset (&args, 0, sizeof args);
151
152   if (!xdr_guestfs_ls_args (xdr_in, &args)) {
153     reply_with_error ("%s: daemon failed to decode procedure arguments", "ls");
154     return;
155   }
156   directory = args.directory;
157
158   r = do_ls (directory);
159   if (r == NULL)
160     /* do_ls has already called reply_with_error, so just return */
161     return;
162
163   struct guestfs_ls_ret ret;
164   ret.listing.listing_len = count_strings (r);
165   ret.listing.listing_val = r;
166   reply ((xdrproc_t) &xdr_guestfs_ls_ret, (char *) &ret);
167   free_strings (r);
168 }
169
170 static void list_devices_stub (XDR *xdr_in)
171 {
172   char **r;
173
174   r = do_list_devices ();
175   if (r == NULL)
176     /* do_list_devices has already called reply_with_error, so just return */
177     return;
178
179   struct guestfs_list_devices_ret ret;
180   ret.devices.devices_len = count_strings (r);
181   ret.devices.devices_val = r;
182   reply ((xdrproc_t) &xdr_guestfs_list_devices_ret, (char *) &ret);
183   free_strings (r);
184 }
185
186 static void list_partitions_stub (XDR *xdr_in)
187 {
188   char **r;
189
190   r = do_list_partitions ();
191   if (r == NULL)
192     /* do_list_partitions has already called reply_with_error, so just return */
193     return;
194
195   struct guestfs_list_partitions_ret ret;
196   ret.partitions.partitions_len = count_strings (r);
197   ret.partitions.partitions_val = r;
198   reply ((xdrproc_t) &xdr_guestfs_list_partitions_ret, (char *) &ret);
199   free_strings (r);
200 }
201
202 static void pvs_stub (XDR *xdr_in)
203 {
204   char **r;
205
206   r = do_pvs ();
207   if (r == NULL)
208     /* do_pvs has already called reply_with_error, so just return */
209     return;
210
211   struct guestfs_pvs_ret ret;
212   ret.physvols.physvols_len = count_strings (r);
213   ret.physvols.physvols_val = r;
214   reply ((xdrproc_t) &xdr_guestfs_pvs_ret, (char *) &ret);
215   free_strings (r);
216 }
217
218 static void vgs_stub (XDR *xdr_in)
219 {
220   char **r;
221
222   r = do_vgs ();
223   if (r == NULL)
224     /* do_vgs has already called reply_with_error, so just return */
225     return;
226
227   struct guestfs_vgs_ret ret;
228   ret.volgroups.volgroups_len = count_strings (r);
229   ret.volgroups.volgroups_val = r;
230   reply ((xdrproc_t) &xdr_guestfs_vgs_ret, (char *) &ret);
231   free_strings (r);
232 }
233
234 static void lvs_stub (XDR *xdr_in)
235 {
236   char **r;
237
238   r = do_lvs ();
239   if (r == NULL)
240     /* do_lvs has already called reply_with_error, so just return */
241     return;
242
243   struct guestfs_lvs_ret ret;
244   ret.logvols.logvols_len = count_strings (r);
245   ret.logvols.logvols_val = r;
246   reply ((xdrproc_t) &xdr_guestfs_lvs_ret, (char *) &ret);
247   free_strings (r);
248 }
249
250 static void pvs_full_stub (XDR *xdr_in)
251 {
252   guestfs_lvm_int_pv_list *r;
253
254   r = do_pvs_full ();
255   if (r == NULL)
256     /* do_pvs_full has already called reply_with_error, so just return */
257     return;
258
259   struct guestfs_pvs_full_ret ret;
260   ret.physvols = *r;
261   reply ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
262   xdr_free ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
263 }
264
265 static void vgs_full_stub (XDR *xdr_in)
266 {
267   guestfs_lvm_int_vg_list *r;
268
269   r = do_vgs_full ();
270   if (r == NULL)
271     /* do_vgs_full has already called reply_with_error, so just return */
272     return;
273
274   struct guestfs_vgs_full_ret ret;
275   ret.volgroups = *r;
276   reply ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
277   xdr_free ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
278 }
279
280 static void lvs_full_stub (XDR *xdr_in)
281 {
282   guestfs_lvm_int_lv_list *r;
283
284   r = do_lvs_full ();
285   if (r == NULL)
286     /* do_lvs_full has already called reply_with_error, so just return */
287     return;
288
289   struct guestfs_lvs_full_ret ret;
290   ret.logvols = *r;
291   reply ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
292   xdr_free ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
293 }
294
295 static void read_lines_stub (XDR *xdr_in)
296 {
297   char **r;
298   struct guestfs_read_lines_args args;
299   const char *path;
300
301   memset (&args, 0, sizeof args);
302
303   if (!xdr_guestfs_read_lines_args (xdr_in, &args)) {
304     reply_with_error ("%s: daemon failed to decode procedure arguments", "read_lines");
305     return;
306   }
307   path = args.path;
308
309   r = do_read_lines (path);
310   if (r == NULL)
311     /* do_read_lines has already called reply_with_error, so just return */
312     return;
313
314   struct guestfs_read_lines_ret ret;
315   ret.lines.lines_len = count_strings (r);
316   ret.lines.lines_val = r;
317   reply ((xdrproc_t) &xdr_guestfs_read_lines_ret, (char *) &ret);
318   free_strings (r);
319 }
320
321 static void aug_init_stub (XDR *xdr_in)
322 {
323   int r;
324   struct guestfs_aug_init_args args;
325   const char *root;
326   int flags;
327
328   memset (&args, 0, sizeof args);
329
330   if (!xdr_guestfs_aug_init_args (xdr_in, &args)) {
331     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_init");
332     return;
333   }
334   root = args.root;
335   flags = args.flags;
336
337   r = do_aug_init (root, flags);
338   if (r == -1)
339     /* do_aug_init has already called reply_with_error, so just return */
340     return;
341
342   reply (NULL, NULL);
343 }
344
345 static void aug_close_stub (XDR *xdr_in)
346 {
347   int r;
348
349   r = do_aug_close ();
350   if (r == -1)
351     /* do_aug_close has already called reply_with_error, so just return */
352     return;
353
354   reply (NULL, NULL);
355 }
356
357 static void aug_defvar_stub (XDR *xdr_in)
358 {
359   int r;
360   struct guestfs_aug_defvar_args args;
361   const char *name;
362   const char *expr;
363
364   memset (&args, 0, sizeof args);
365
366   if (!xdr_guestfs_aug_defvar_args (xdr_in, &args)) {
367     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defvar");
368     return;
369   }
370   name = args.name;
371   expr = args.expr ? *args.expr : NULL;
372
373   r = do_aug_defvar (name, expr);
374   if (r == -1)
375     /* do_aug_defvar has already called reply_with_error, so just return */
376     return;
377
378   struct guestfs_aug_defvar_ret ret;
379   ret.nrnodes = r;
380   reply ((xdrproc_t) &xdr_guestfs_aug_defvar_ret, (char *) &ret);
381 }
382
383 static void aug_defnode_stub (XDR *xdr_in)
384 {
385   guestfs_aug_defnode_ret *r;
386   struct guestfs_aug_defnode_args args;
387   const char *name;
388   const char *expr;
389   const char *val;
390
391   memset (&args, 0, sizeof args);
392
393   if (!xdr_guestfs_aug_defnode_args (xdr_in, &args)) {
394     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defnode");
395     return;
396   }
397   name = args.name;
398   expr = args.expr;
399   val = args.val;
400
401   r = do_aug_defnode (name, expr, val);
402   if (r == NULL)
403     /* do_aug_defnode has already called reply_with_error, so just return */
404     return;
405
406   reply ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
407   xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
408 }
409
410 static void aug_get_stub (XDR *xdr_in)
411 {
412   char *r;
413   struct guestfs_aug_get_args args;
414   const char *path;
415
416   memset (&args, 0, sizeof args);
417
418   if (!xdr_guestfs_aug_get_args (xdr_in, &args)) {
419     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_get");
420     return;
421   }
422   path = args.path;
423
424   r = do_aug_get (path);
425   if (r == NULL)
426     /* do_aug_get has already called reply_with_error, so just return */
427     return;
428
429   struct guestfs_aug_get_ret ret;
430   ret.val = r;
431   reply ((xdrproc_t) &xdr_guestfs_aug_get_ret, (char *) &ret);
432   free (r);
433 }
434
435 static void aug_set_stub (XDR *xdr_in)
436 {
437   int r;
438   struct guestfs_aug_set_args args;
439   const char *path;
440   const char *val;
441
442   memset (&args, 0, sizeof args);
443
444   if (!xdr_guestfs_aug_set_args (xdr_in, &args)) {
445     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_set");
446     return;
447   }
448   path = args.path;
449   val = args.val;
450
451   r = do_aug_set (path, val);
452   if (r == -1)
453     /* do_aug_set has already called reply_with_error, so just return */
454     return;
455
456   reply (NULL, NULL);
457 }
458
459 static void aug_insert_stub (XDR *xdr_in)
460 {
461   int r;
462   struct guestfs_aug_insert_args args;
463   const char *path;
464   const char *label;
465   int before;
466
467   memset (&args, 0, sizeof args);
468
469   if (!xdr_guestfs_aug_insert_args (xdr_in, &args)) {
470     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_insert");
471     return;
472   }
473   path = args.path;
474   label = args.label;
475   before = args.before;
476
477   r = do_aug_insert (path, label, before);
478   if (r == -1)
479     /* do_aug_insert has already called reply_with_error, so just return */
480     return;
481
482   reply (NULL, NULL);
483 }
484
485 static void aug_rm_stub (XDR *xdr_in)
486 {
487   int r;
488   struct guestfs_aug_rm_args args;
489   const char *path;
490
491   memset (&args, 0, sizeof args);
492
493   if (!xdr_guestfs_aug_rm_args (xdr_in, &args)) {
494     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_rm");
495     return;
496   }
497   path = args.path;
498
499   r = do_aug_rm (path);
500   if (r == -1)
501     /* do_aug_rm has already called reply_with_error, so just return */
502     return;
503
504   struct guestfs_aug_rm_ret ret;
505   ret.nrnodes = r;
506   reply ((xdrproc_t) &xdr_guestfs_aug_rm_ret, (char *) &ret);
507 }
508
509 static void aug_mv_stub (XDR *xdr_in)
510 {
511   int r;
512   struct guestfs_aug_mv_args args;
513   const char *src;
514   const char *dest;
515
516   memset (&args, 0, sizeof args);
517
518   if (!xdr_guestfs_aug_mv_args (xdr_in, &args)) {
519     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_mv");
520     return;
521   }
522   src = args.src;
523   dest = args.dest;
524
525   r = do_aug_mv (src, dest);
526   if (r == -1)
527     /* do_aug_mv has already called reply_with_error, so just return */
528     return;
529
530   reply (NULL, NULL);
531 }
532
533 static void aug_match_stub (XDR *xdr_in)
534 {
535   char **r;
536   struct guestfs_aug_match_args args;
537   const char *path;
538
539   memset (&args, 0, sizeof args);
540
541   if (!xdr_guestfs_aug_match_args (xdr_in, &args)) {
542     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_match");
543     return;
544   }
545   path = args.path;
546
547   r = do_aug_match (path);
548   if (r == NULL)
549     /* do_aug_match has already called reply_with_error, so just return */
550     return;
551
552   struct guestfs_aug_match_ret ret;
553   ret.matches.matches_len = count_strings (r);
554   ret.matches.matches_val = r;
555   reply ((xdrproc_t) &xdr_guestfs_aug_match_ret, (char *) &ret);
556   free_strings (r);
557 }
558
559 static void aug_save_stub (XDR *xdr_in)
560 {
561   int r;
562
563   r = do_aug_save ();
564   if (r == -1)
565     /* do_aug_save has already called reply_with_error, so just return */
566     return;
567
568   reply (NULL, NULL);
569 }
570
571 static void aug_load_stub (XDR *xdr_in)
572 {
573   int r;
574
575   r = do_aug_load ();
576   if (r == -1)
577     /* do_aug_load has already called reply_with_error, so just return */
578     return;
579
580   reply (NULL, NULL);
581 }
582
583 void dispatch_incoming_message (XDR *xdr_in)
584 {
585   switch (proc_nr) {
586     case GUESTFS_PROC_MOUNT:
587       mount_stub (xdr_in);
588       break;
589     case GUESTFS_PROC_SYNC:
590       sync_stub (xdr_in);
591       break;
592     case GUESTFS_PROC_TOUCH:
593       touch_stub (xdr_in);
594       break;
595     case GUESTFS_PROC_CAT:
596       cat_stub (xdr_in);
597       break;
598     case GUESTFS_PROC_LL:
599       ll_stub (xdr_in);
600       break;
601     case GUESTFS_PROC_LS:
602       ls_stub (xdr_in);
603       break;
604     case GUESTFS_PROC_LIST_DEVICES:
605       list_devices_stub (xdr_in);
606       break;
607     case GUESTFS_PROC_LIST_PARTITIONS:
608       list_partitions_stub (xdr_in);
609       break;
610     case GUESTFS_PROC_PVS:
611       pvs_stub (xdr_in);
612       break;
613     case GUESTFS_PROC_VGS:
614       vgs_stub (xdr_in);
615       break;
616     case GUESTFS_PROC_LVS:
617       lvs_stub (xdr_in);
618       break;
619     case GUESTFS_PROC_PVS_FULL:
620       pvs_full_stub (xdr_in);
621       break;
622     case GUESTFS_PROC_VGS_FULL:
623       vgs_full_stub (xdr_in);
624       break;
625     case GUESTFS_PROC_LVS_FULL:
626       lvs_full_stub (xdr_in);
627       break;
628     case GUESTFS_PROC_READ_LINES:
629       read_lines_stub (xdr_in);
630       break;
631     case GUESTFS_PROC_AUG_INIT:
632       aug_init_stub (xdr_in);
633       break;
634     case GUESTFS_PROC_AUG_CLOSE:
635       aug_close_stub (xdr_in);
636       break;
637     case GUESTFS_PROC_AUG_DEFVAR:
638       aug_defvar_stub (xdr_in);
639       break;
640     case GUESTFS_PROC_AUG_DEFNODE:
641       aug_defnode_stub (xdr_in);
642       break;
643     case GUESTFS_PROC_AUG_GET:
644       aug_get_stub (xdr_in);
645       break;
646     case GUESTFS_PROC_AUG_SET:
647       aug_set_stub (xdr_in);
648       break;
649     case GUESTFS_PROC_AUG_INSERT:
650       aug_insert_stub (xdr_in);
651       break;
652     case GUESTFS_PROC_AUG_RM:
653       aug_rm_stub (xdr_in);
654       break;
655     case GUESTFS_PROC_AUG_MV:
656       aug_mv_stub (xdr_in);
657       break;
658     case GUESTFS_PROC_AUG_MATCH:
659       aug_match_stub (xdr_in);
660       break;
661     case GUESTFS_PROC_AUG_SAVE:
662       aug_save_stub (xdr_in);
663       break;
664     case GUESTFS_PROC_AUG_LOAD:
665       aug_load_stub (xdr_in);
666       break;
667     default:
668       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
669   }
670 }
671
672 static const char *lvm_pv_cols = "pv_name,pv_uuid,pv_fmt,pv_size,dev_size,pv_free,pv_used,pv_attr,pv_pe_count,pv_pe_alloc_count,pv_tags,pe_start,pv_mda_count,pv_mda_free";
673
674 static int lvm_tokenize_pv (char *str, struct guestfs_lvm_int_pv *r)
675 {
676   char *tok, *p, *next;
677   int i, j;
678
679   if (!str) {
680     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
681     return -1;
682   }
683   if (!*str || isspace (*str)) {
684     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
685     return -1;
686   }
687   tok = str;
688   if (!tok) {
689     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_name");
690     return -1;
691   }
692   p = strchrnul (tok, ',');
693   if (*p) next = p+1; else next = NULL;
694   *p = '\0';
695   r->pv_name = strdup (tok);
696   if (r->pv_name == NULL) {
697     perror ("strdup");
698     return -1;
699   }
700   tok = next;
701   if (!tok) {
702     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_uuid");
703     return -1;
704   }
705   p = strchrnul (tok, ',');
706   if (*p) next = p+1; else next = NULL;
707   *p = '\0';
708   for (i = j = 0; i < 32; ++j) {
709     if (tok[j] == '\0') {
710       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
711       return -1;
712     } else if (tok[j] != '-')
713       r->pv_uuid[i++] = tok[j];
714   }
715   tok = next;
716   if (!tok) {
717     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_fmt");
718     return -1;
719   }
720   p = strchrnul (tok, ',');
721   if (*p) next = p+1; else next = NULL;
722   *p = '\0';
723   r->pv_fmt = strdup (tok);
724   if (r->pv_fmt == NULL) {
725     perror ("strdup");
726     return -1;
727   }
728   tok = next;
729   if (!tok) {
730     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_size");
731     return -1;
732   }
733   p = strchrnul (tok, ',');
734   if (*p) next = p+1; else next = NULL;
735   *p = '\0';
736   if (sscanf (tok, "%"SCNu64, &r->pv_size) != 1) {
737     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_size");
738     return -1;
739   }
740   tok = next;
741   if (!tok) {
742     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "dev_size");
743     return -1;
744   }
745   p = strchrnul (tok, ',');
746   if (*p) next = p+1; else next = NULL;
747   *p = '\0';
748   if (sscanf (tok, "%"SCNu64, &r->dev_size) != 1) {
749     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "dev_size");
750     return -1;
751   }
752   tok = next;
753   if (!tok) {
754     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_free");
755     return -1;
756   }
757   p = strchrnul (tok, ',');
758   if (*p) next = p+1; else next = NULL;
759   *p = '\0';
760   if (sscanf (tok, "%"SCNu64, &r->pv_free) != 1) {
761     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_free");
762     return -1;
763   }
764   tok = next;
765   if (!tok) {
766     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_used");
767     return -1;
768   }
769   p = strchrnul (tok, ',');
770   if (*p) next = p+1; else next = NULL;
771   *p = '\0';
772   if (sscanf (tok, "%"SCNu64, &r->pv_used) != 1) {
773     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_used");
774     return -1;
775   }
776   tok = next;
777   if (!tok) {
778     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_attr");
779     return -1;
780   }
781   p = strchrnul (tok, ',');
782   if (*p) next = p+1; else next = NULL;
783   *p = '\0';
784   r->pv_attr = strdup (tok);
785   if (r->pv_attr == NULL) {
786     perror ("strdup");
787     return -1;
788   }
789   tok = next;
790   if (!tok) {
791     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_count");
792     return -1;
793   }
794   p = strchrnul (tok, ',');
795   if (*p) next = p+1; else next = NULL;
796   *p = '\0';
797   if (sscanf (tok, "%"SCNi64, &r->pv_pe_count) != 1) {
798     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_count");
799     return -1;
800   }
801   tok = next;
802   if (!tok) {
803     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_alloc_count");
804     return -1;
805   }
806   p = strchrnul (tok, ',');
807   if (*p) next = p+1; else next = NULL;
808   *p = '\0';
809   if (sscanf (tok, "%"SCNi64, &r->pv_pe_alloc_count) != 1) {
810     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_alloc_count");
811     return -1;
812   }
813   tok = next;
814   if (!tok) {
815     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_tags");
816     return -1;
817   }
818   p = strchrnul (tok, ',');
819   if (*p) next = p+1; else next = NULL;
820   *p = '\0';
821   r->pv_tags = strdup (tok);
822   if (r->pv_tags == NULL) {
823     perror ("strdup");
824     return -1;
825   }
826   tok = next;
827   if (!tok) {
828     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pe_start");
829     return -1;
830   }
831   p = strchrnul (tok, ',');
832   if (*p) next = p+1; else next = NULL;
833   *p = '\0';
834   if (sscanf (tok, "%"SCNu64, &r->pe_start) != 1) {
835     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pe_start");
836     return -1;
837   }
838   tok = next;
839   if (!tok) {
840     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_count");
841     return -1;
842   }
843   p = strchrnul (tok, ',');
844   if (*p) next = p+1; else next = NULL;
845   *p = '\0';
846   if (sscanf (tok, "%"SCNi64, &r->pv_mda_count) != 1) {
847     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_mda_count");
848     return -1;
849   }
850   tok = next;
851   if (!tok) {
852     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_free");
853     return -1;
854   }
855   p = strchrnul (tok, ',');
856   if (*p) next = p+1; else next = NULL;
857   *p = '\0';
858   if (sscanf (tok, "%"SCNu64, &r->pv_mda_free) != 1) {
859     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_mda_free");
860     return -1;
861   }
862   tok = next;
863   if (tok != NULL) {
864     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
865     return -1;
866   }
867   return 0;
868 }
869
870 guestfs_lvm_int_pv_list *
871 parse_command_line_pvs (void)
872 {
873   char *out, *err;
874   char *p, *pend;
875   int r, i;
876   guestfs_lvm_int_pv_list *ret;
877   void *newp;
878
879   ret = malloc (sizeof *ret);
880   if (!ret) {
881     reply_with_perror ("malloc");
882     return NULL;
883   }
884
885   ret->guestfs_lvm_int_pv_list_len = 0;
886   ret->guestfs_lvm_int_pv_list_val = NULL;
887
888   r = command (&out, &err,
889                "/sbin/lvm", "pvs",
890                "-o", lvm_pv_cols, "--unbuffered", "--noheadings",
891                "--nosuffix", "--separator", ",", "--units", "b", NULL);
892   if (r == -1) {
893     reply_with_error ("%s", err);
894     free (out);
895     free (err);
896     return NULL;
897   }
898
899   free (err);
900
901   /* Tokenize each line of the output. */
902   p = out;
903   i = 0;
904   while (p) {
905     pend = strchr (p, '\n');    /* Get the next line of output. */
906     if (pend) {
907       *pend = '\0';
908       pend++;
909     }
910
911     while (*p && isspace (*p))  /* Skip any leading whitespace. */
912       p++;
913
914     if (!*p) {                  /* Empty line?  Skip it. */
915       p = pend;
916       continue;
917     }
918
919     /* Allocate some space to store this next entry. */
920     newp = realloc (ret->guestfs_lvm_int_pv_list_val,
921                     sizeof (guestfs_lvm_int_pv) * (i+1));
922     if (newp == NULL) {
923       reply_with_perror ("realloc");
924       free (ret->guestfs_lvm_int_pv_list_val);
925       free (ret);
926       free (out);
927       return NULL;
928     }
929     ret->guestfs_lvm_int_pv_list_val = newp;
930
931     /* Tokenize the next entry. */
932     r = lvm_tokenize_pv (p, &ret->guestfs_lvm_int_pv_list_val[i]);
933     if (r == -1) {
934       reply_with_error ("failed to parse output of 'pvs' command");
935       free (ret->guestfs_lvm_int_pv_list_val);
936       free (ret);
937       free (out);
938       return NULL;
939     }
940
941     ++i;
942     p = pend;
943   }
944
945   ret->guestfs_lvm_int_pv_list_len = i;
946
947   free (out);
948   return ret;
949 }
950 static const char *lvm_vg_cols = "vg_name,vg_uuid,vg_fmt,vg_attr,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_tags,vg_mda_count,vg_mda_free";
951
952 static int lvm_tokenize_vg (char *str, struct guestfs_lvm_int_vg *r)
953 {
954   char *tok, *p, *next;
955   int i, j;
956
957   if (!str) {
958     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
959     return -1;
960   }
961   if (!*str || isspace (*str)) {
962     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
963     return -1;
964   }
965   tok = str;
966   if (!tok) {
967     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_name");
968     return -1;
969   }
970   p = strchrnul (tok, ',');
971   if (*p) next = p+1; else next = NULL;
972   *p = '\0';
973   r->vg_name = strdup (tok);
974   if (r->vg_name == NULL) {
975     perror ("strdup");
976     return -1;
977   }
978   tok = next;
979   if (!tok) {
980     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_uuid");
981     return -1;
982   }
983   p = strchrnul (tok, ',');
984   if (*p) next = p+1; else next = NULL;
985   *p = '\0';
986   for (i = j = 0; i < 32; ++j) {
987     if (tok[j] == '\0') {
988       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
989       return -1;
990     } else if (tok[j] != '-')
991       r->vg_uuid[i++] = tok[j];
992   }
993   tok = next;
994   if (!tok) {
995     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_fmt");
996     return -1;
997   }
998   p = strchrnul (tok, ',');
999   if (*p) next = p+1; else next = NULL;
1000   *p = '\0';
1001   r->vg_fmt = strdup (tok);
1002   if (r->vg_fmt == NULL) {
1003     perror ("strdup");
1004     return -1;
1005   }
1006   tok = next;
1007   if (!tok) {
1008     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_attr");
1009     return -1;
1010   }
1011   p = strchrnul (tok, ',');
1012   if (*p) next = p+1; else next = NULL;
1013   *p = '\0';
1014   r->vg_attr = strdup (tok);
1015   if (r->vg_attr == NULL) {
1016     perror ("strdup");
1017     return -1;
1018   }
1019   tok = next;
1020   if (!tok) {
1021     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_size");
1022     return -1;
1023   }
1024   p = strchrnul (tok, ',');
1025   if (*p) next = p+1; else next = NULL;
1026   *p = '\0';
1027   if (sscanf (tok, "%"SCNu64, &r->vg_size) != 1) {
1028     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_size");
1029     return -1;
1030   }
1031   tok = next;
1032   if (!tok) {
1033     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free");
1034     return -1;
1035   }
1036   p = strchrnul (tok, ',');
1037   if (*p) next = p+1; else next = NULL;
1038   *p = '\0';
1039   if (sscanf (tok, "%"SCNu64, &r->vg_free) != 1) {
1040     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_free");
1041     return -1;
1042   }
1043   tok = next;
1044   if (!tok) {
1045     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_sysid");
1046     return -1;
1047   }
1048   p = strchrnul (tok, ',');
1049   if (*p) next = p+1; else next = NULL;
1050   *p = '\0';
1051   r->vg_sysid = strdup (tok);
1052   if (r->vg_sysid == NULL) {
1053     perror ("strdup");
1054     return -1;
1055   }
1056   tok = next;
1057   if (!tok) {
1058     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_size");
1059     return -1;
1060   }
1061   p = strchrnul (tok, ',');
1062   if (*p) next = p+1; else next = NULL;
1063   *p = '\0';
1064   if (sscanf (tok, "%"SCNu64, &r->vg_extent_size) != 1) {
1065     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_extent_size");
1066     return -1;
1067   }
1068   tok = next;
1069   if (!tok) {
1070     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_count");
1071     return -1;
1072   }
1073   p = strchrnul (tok, ',');
1074   if (*p) next = p+1; else next = NULL;
1075   *p = '\0';
1076   if (sscanf (tok, "%"SCNi64, &r->vg_extent_count) != 1) {
1077     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_extent_count");
1078     return -1;
1079   }
1080   tok = next;
1081   if (!tok) {
1082     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free_count");
1083     return -1;
1084   }
1085   p = strchrnul (tok, ',');
1086   if (*p) next = p+1; else next = NULL;
1087   *p = '\0';
1088   if (sscanf (tok, "%"SCNi64, &r->vg_free_count) != 1) {
1089     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_free_count");
1090     return -1;
1091   }
1092   tok = next;
1093   if (!tok) {
1094     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_lv");
1095     return -1;
1096   }
1097   p = strchrnul (tok, ',');
1098   if (*p) next = p+1; else next = NULL;
1099   *p = '\0';
1100   if (sscanf (tok, "%"SCNi64, &r->max_lv) != 1) {
1101     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_lv");
1102     return -1;
1103   }
1104   tok = next;
1105   if (!tok) {
1106     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_pv");
1107     return -1;
1108   }
1109   p = strchrnul (tok, ',');
1110   if (*p) next = p+1; else next = NULL;
1111   *p = '\0';
1112   if (sscanf (tok, "%"SCNi64, &r->max_pv) != 1) {
1113     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_pv");
1114     return -1;
1115   }
1116   tok = next;
1117   if (!tok) {
1118     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_count");
1119     return -1;
1120   }
1121   p = strchrnul (tok, ',');
1122   if (*p) next = p+1; else next = NULL;
1123   *p = '\0';
1124   if (sscanf (tok, "%"SCNi64, &r->pv_count) != 1) {
1125     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_count");
1126     return -1;
1127   }
1128   tok = next;
1129   if (!tok) {
1130     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_count");
1131     return -1;
1132   }
1133   p = strchrnul (tok, ',');
1134   if (*p) next = p+1; else next = NULL;
1135   *p = '\0';
1136   if (sscanf (tok, "%"SCNi64, &r->lv_count) != 1) {
1137     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_count");
1138     return -1;
1139   }
1140   tok = next;
1141   if (!tok) {
1142     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_count");
1143     return -1;
1144   }
1145   p = strchrnul (tok, ',');
1146   if (*p) next = p+1; else next = NULL;
1147   *p = '\0';
1148   if (sscanf (tok, "%"SCNi64, &r->snap_count) != 1) {
1149     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "snap_count");
1150     return -1;
1151   }
1152   tok = next;
1153   if (!tok) {
1154     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_seqno");
1155     return -1;
1156   }
1157   p = strchrnul (tok, ',');
1158   if (*p) next = p+1; else next = NULL;
1159   *p = '\0';
1160   if (sscanf (tok, "%"SCNi64, &r->vg_seqno) != 1) {
1161     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_seqno");
1162     return -1;
1163   }
1164   tok = next;
1165   if (!tok) {
1166     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_tags");
1167     return -1;
1168   }
1169   p = strchrnul (tok, ',');
1170   if (*p) next = p+1; else next = NULL;
1171   *p = '\0';
1172   r->vg_tags = strdup (tok);
1173   if (r->vg_tags == NULL) {
1174     perror ("strdup");
1175     return -1;
1176   }
1177   tok = next;
1178   if (!tok) {
1179     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_count");
1180     return -1;
1181   }
1182   p = strchrnul (tok, ',');
1183   if (*p) next = p+1; else next = NULL;
1184   *p = '\0';
1185   if (sscanf (tok, "%"SCNi64, &r->vg_mda_count) != 1) {
1186     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_mda_count");
1187     return -1;
1188   }
1189   tok = next;
1190   if (!tok) {
1191     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_free");
1192     return -1;
1193   }
1194   p = strchrnul (tok, ',');
1195   if (*p) next = p+1; else next = NULL;
1196   *p = '\0';
1197   if (sscanf (tok, "%"SCNu64, &r->vg_mda_free) != 1) {
1198     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_mda_free");
1199     return -1;
1200   }
1201   tok = next;
1202   if (tok != NULL) {
1203     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1204     return -1;
1205   }
1206   return 0;
1207 }
1208
1209 guestfs_lvm_int_vg_list *
1210 parse_command_line_vgs (void)
1211 {
1212   char *out, *err;
1213   char *p, *pend;
1214   int r, i;
1215   guestfs_lvm_int_vg_list *ret;
1216   void *newp;
1217
1218   ret = malloc (sizeof *ret);
1219   if (!ret) {
1220     reply_with_perror ("malloc");
1221     return NULL;
1222   }
1223
1224   ret->guestfs_lvm_int_vg_list_len = 0;
1225   ret->guestfs_lvm_int_vg_list_val = NULL;
1226
1227   r = command (&out, &err,
1228                "/sbin/lvm", "vgs",
1229                "-o", lvm_vg_cols, "--unbuffered", "--noheadings",
1230                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1231   if (r == -1) {
1232     reply_with_error ("%s", err);
1233     free (out);
1234     free (err);
1235     return NULL;
1236   }
1237
1238   free (err);
1239
1240   /* Tokenize each line of the output. */
1241   p = out;
1242   i = 0;
1243   while (p) {
1244     pend = strchr (p, '\n');    /* Get the next line of output. */
1245     if (pend) {
1246       *pend = '\0';
1247       pend++;
1248     }
1249
1250     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1251       p++;
1252
1253     if (!*p) {                  /* Empty line?  Skip it. */
1254       p = pend;
1255       continue;
1256     }
1257
1258     /* Allocate some space to store this next entry. */
1259     newp = realloc (ret->guestfs_lvm_int_vg_list_val,
1260                     sizeof (guestfs_lvm_int_vg) * (i+1));
1261     if (newp == NULL) {
1262       reply_with_perror ("realloc");
1263       free (ret->guestfs_lvm_int_vg_list_val);
1264       free (ret);
1265       free (out);
1266       return NULL;
1267     }
1268     ret->guestfs_lvm_int_vg_list_val = newp;
1269
1270     /* Tokenize the next entry. */
1271     r = lvm_tokenize_vg (p, &ret->guestfs_lvm_int_vg_list_val[i]);
1272     if (r == -1) {
1273       reply_with_error ("failed to parse output of 'vgs' command");
1274       free (ret->guestfs_lvm_int_vg_list_val);
1275       free (ret);
1276       free (out);
1277       return NULL;
1278     }
1279
1280     ++i;
1281     p = pend;
1282   }
1283
1284   ret->guestfs_lvm_int_vg_list_len = i;
1285
1286   free (out);
1287   return ret;
1288 }
1289 static const char *lvm_lv_cols = "lv_name,lv_uuid,lv_attr,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,lv_size,seg_count,origin,snap_percent,copy_percent,move_pv,lv_tags,mirror_log,modules";
1290
1291 static int lvm_tokenize_lv (char *str, struct guestfs_lvm_int_lv *r)
1292 {
1293   char *tok, *p, *next;
1294   int i, j;
1295
1296   if (!str) {
1297     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
1298     return -1;
1299   }
1300   if (!*str || isspace (*str)) {
1301     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
1302     return -1;
1303   }
1304   tok = str;
1305   if (!tok) {
1306     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_name");
1307     return -1;
1308   }
1309   p = strchrnul (tok, ',');
1310   if (*p) next = p+1; else next = NULL;
1311   *p = '\0';
1312   r->lv_name = strdup (tok);
1313   if (r->lv_name == NULL) {
1314     perror ("strdup");
1315     return -1;
1316   }
1317   tok = next;
1318   if (!tok) {
1319     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_uuid");
1320     return -1;
1321   }
1322   p = strchrnul (tok, ',');
1323   if (*p) next = p+1; else next = NULL;
1324   *p = '\0';
1325   for (i = j = 0; i < 32; ++j) {
1326     if (tok[j] == '\0') {
1327       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1328       return -1;
1329     } else if (tok[j] != '-')
1330       r->lv_uuid[i++] = tok[j];
1331   }
1332   tok = next;
1333   if (!tok) {
1334     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_attr");
1335     return -1;
1336   }
1337   p = strchrnul (tok, ',');
1338   if (*p) next = p+1; else next = NULL;
1339   *p = '\0';
1340   r->lv_attr = strdup (tok);
1341   if (r->lv_attr == NULL) {
1342     perror ("strdup");
1343     return -1;
1344   }
1345   tok = next;
1346   if (!tok) {
1347     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_major");
1348     return -1;
1349   }
1350   p = strchrnul (tok, ',');
1351   if (*p) next = p+1; else next = NULL;
1352   *p = '\0';
1353   if (sscanf (tok, "%"SCNi64, &r->lv_major) != 1) {
1354     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_major");
1355     return -1;
1356   }
1357   tok = next;
1358   if (!tok) {
1359     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_minor");
1360     return -1;
1361   }
1362   p = strchrnul (tok, ',');
1363   if (*p) next = p+1; else next = NULL;
1364   *p = '\0';
1365   if (sscanf (tok, "%"SCNi64, &r->lv_minor) != 1) {
1366     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_minor");
1367     return -1;
1368   }
1369   tok = next;
1370   if (!tok) {
1371     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_major");
1372     return -1;
1373   }
1374   p = strchrnul (tok, ',');
1375   if (*p) next = p+1; else next = NULL;
1376   *p = '\0';
1377   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_major) != 1) {
1378     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_major");
1379     return -1;
1380   }
1381   tok = next;
1382   if (!tok) {
1383     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_minor");
1384     return -1;
1385   }
1386   p = strchrnul (tok, ',');
1387   if (*p) next = p+1; else next = NULL;
1388   *p = '\0';
1389   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_minor) != 1) {
1390     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_minor");
1391     return -1;
1392   }
1393   tok = next;
1394   if (!tok) {
1395     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_size");
1396     return -1;
1397   }
1398   p = strchrnul (tok, ',');
1399   if (*p) next = p+1; else next = NULL;
1400   *p = '\0';
1401   if (sscanf (tok, "%"SCNu64, &r->lv_size) != 1) {
1402     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "lv_size");
1403     return -1;
1404   }
1405   tok = next;
1406   if (!tok) {
1407     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "seg_count");
1408     return -1;
1409   }
1410   p = strchrnul (tok, ',');
1411   if (*p) next = p+1; else next = NULL;
1412   *p = '\0';
1413   if (sscanf (tok, "%"SCNi64, &r->seg_count) != 1) {
1414     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "seg_count");
1415     return -1;
1416   }
1417   tok = next;
1418   if (!tok) {
1419     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "origin");
1420     return -1;
1421   }
1422   p = strchrnul (tok, ',');
1423   if (*p) next = p+1; else next = NULL;
1424   *p = '\0';
1425   r->origin = strdup (tok);
1426   if (r->origin == NULL) {
1427     perror ("strdup");
1428     return -1;
1429   }
1430   tok = next;
1431   if (!tok) {
1432     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_percent");
1433     return -1;
1434   }
1435   p = strchrnul (tok, ',');
1436   if (*p) next = p+1; else next = NULL;
1437   *p = '\0';
1438   if (tok[0] == '\0')
1439     r->snap_percent = -1;
1440   else if (sscanf (tok, "%f", &r->snap_percent) != 1) {
1441     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "snap_percent");
1442     return -1;
1443   }
1444   tok = next;
1445   if (!tok) {
1446     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "copy_percent");
1447     return -1;
1448   }
1449   p = strchrnul (tok, ',');
1450   if (*p) next = p+1; else next = NULL;
1451   *p = '\0';
1452   if (tok[0] == '\0')
1453     r->copy_percent = -1;
1454   else if (sscanf (tok, "%f", &r->copy_percent) != 1) {
1455     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "copy_percent");
1456     return -1;
1457   }
1458   tok = next;
1459   if (!tok) {
1460     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "move_pv");
1461     return -1;
1462   }
1463   p = strchrnul (tok, ',');
1464   if (*p) next = p+1; else next = NULL;
1465   *p = '\0';
1466   r->move_pv = strdup (tok);
1467   if (r->move_pv == NULL) {
1468     perror ("strdup");
1469     return -1;
1470   }
1471   tok = next;
1472   if (!tok) {
1473     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_tags");
1474     return -1;
1475   }
1476   p = strchrnul (tok, ',');
1477   if (*p) next = p+1; else next = NULL;
1478   *p = '\0';
1479   r->lv_tags = strdup (tok);
1480   if (r->lv_tags == NULL) {
1481     perror ("strdup");
1482     return -1;
1483   }
1484   tok = next;
1485   if (!tok) {
1486     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "mirror_log");
1487     return -1;
1488   }
1489   p = strchrnul (tok, ',');
1490   if (*p) next = p+1; else next = NULL;
1491   *p = '\0';
1492   r->mirror_log = strdup (tok);
1493   if (r->mirror_log == NULL) {
1494     perror ("strdup");
1495     return -1;
1496   }
1497   tok = next;
1498   if (!tok) {
1499     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "modules");
1500     return -1;
1501   }
1502   p = strchrnul (tok, ',');
1503   if (*p) next = p+1; else next = NULL;
1504   *p = '\0';
1505   r->modules = strdup (tok);
1506   if (r->modules == NULL) {
1507     perror ("strdup");
1508     return -1;
1509   }
1510   tok = next;
1511   if (tok != NULL) {
1512     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1513     return -1;
1514   }
1515   return 0;
1516 }
1517
1518 guestfs_lvm_int_lv_list *
1519 parse_command_line_lvs (void)
1520 {
1521   char *out, *err;
1522   char *p, *pend;
1523   int r, i;
1524   guestfs_lvm_int_lv_list *ret;
1525   void *newp;
1526
1527   ret = malloc (sizeof *ret);
1528   if (!ret) {
1529     reply_with_perror ("malloc");
1530     return NULL;
1531   }
1532
1533   ret->guestfs_lvm_int_lv_list_len = 0;
1534   ret->guestfs_lvm_int_lv_list_val = NULL;
1535
1536   r = command (&out, &err,
1537                "/sbin/lvm", "lvs",
1538                "-o", lvm_lv_cols, "--unbuffered", "--noheadings",
1539                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1540   if (r == -1) {
1541     reply_with_error ("%s", err);
1542     free (out);
1543     free (err);
1544     return NULL;
1545   }
1546
1547   free (err);
1548
1549   /* Tokenize each line of the output. */
1550   p = out;
1551   i = 0;
1552   while (p) {
1553     pend = strchr (p, '\n');    /* Get the next line of output. */
1554     if (pend) {
1555       *pend = '\0';
1556       pend++;
1557     }
1558
1559     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1560       p++;
1561
1562     if (!*p) {                  /* Empty line?  Skip it. */
1563       p = pend;
1564       continue;
1565     }
1566
1567     /* Allocate some space to store this next entry. */
1568     newp = realloc (ret->guestfs_lvm_int_lv_list_val,
1569                     sizeof (guestfs_lvm_int_lv) * (i+1));
1570     if (newp == NULL) {
1571       reply_with_perror ("realloc");
1572       free (ret->guestfs_lvm_int_lv_list_val);
1573       free (ret);
1574       free (out);
1575       return NULL;
1576     }
1577     ret->guestfs_lvm_int_lv_list_val = newp;
1578
1579     /* Tokenize the next entry. */
1580     r = lvm_tokenize_lv (p, &ret->guestfs_lvm_int_lv_list_val[i]);
1581     if (r == -1) {
1582       reply_with_error ("failed to parse output of 'lvs' command");
1583       free (ret->guestfs_lvm_int_lv_list_val);
1584       free (ret);
1585       free (out);
1586       return NULL;
1587     }
1588
1589     ++i;
1590     p = pend;
1591   }
1592
1593   ret->guestfs_lvm_int_lv_list_len = i;
1594
1595   free (out);
1596   return ret;
1597 }