eb3982811df515c14857ca318f1a4898931e172d
[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 static void aug_ls_stub (XDR *xdr_in)
584 {
585   char **r;
586   struct guestfs_aug_ls_args args;
587   const char *path;
588
589   memset (&args, 0, sizeof args);
590
591   if (!xdr_guestfs_aug_ls_args (xdr_in, &args)) {
592     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_ls");
593     return;
594   }
595   path = args.path;
596
597   r = do_aug_ls (path);
598   if (r == NULL)
599     /* do_aug_ls has already called reply_with_error, so just return */
600     return;
601
602   struct guestfs_aug_ls_ret ret;
603   ret.matches.matches_len = count_strings (r);
604   ret.matches.matches_val = r;
605   reply ((xdrproc_t) &xdr_guestfs_aug_ls_ret, (char *) &ret);
606   free_strings (r);
607 }
608
609 void dispatch_incoming_message (XDR *xdr_in)
610 {
611   switch (proc_nr) {
612     case GUESTFS_PROC_MOUNT:
613       mount_stub (xdr_in);
614       break;
615     case GUESTFS_PROC_SYNC:
616       sync_stub (xdr_in);
617       break;
618     case GUESTFS_PROC_TOUCH:
619       touch_stub (xdr_in);
620       break;
621     case GUESTFS_PROC_CAT:
622       cat_stub (xdr_in);
623       break;
624     case GUESTFS_PROC_LL:
625       ll_stub (xdr_in);
626       break;
627     case GUESTFS_PROC_LS:
628       ls_stub (xdr_in);
629       break;
630     case GUESTFS_PROC_LIST_DEVICES:
631       list_devices_stub (xdr_in);
632       break;
633     case GUESTFS_PROC_LIST_PARTITIONS:
634       list_partitions_stub (xdr_in);
635       break;
636     case GUESTFS_PROC_PVS:
637       pvs_stub (xdr_in);
638       break;
639     case GUESTFS_PROC_VGS:
640       vgs_stub (xdr_in);
641       break;
642     case GUESTFS_PROC_LVS:
643       lvs_stub (xdr_in);
644       break;
645     case GUESTFS_PROC_PVS_FULL:
646       pvs_full_stub (xdr_in);
647       break;
648     case GUESTFS_PROC_VGS_FULL:
649       vgs_full_stub (xdr_in);
650       break;
651     case GUESTFS_PROC_LVS_FULL:
652       lvs_full_stub (xdr_in);
653       break;
654     case GUESTFS_PROC_READ_LINES:
655       read_lines_stub (xdr_in);
656       break;
657     case GUESTFS_PROC_AUG_INIT:
658       aug_init_stub (xdr_in);
659       break;
660     case GUESTFS_PROC_AUG_CLOSE:
661       aug_close_stub (xdr_in);
662       break;
663     case GUESTFS_PROC_AUG_DEFVAR:
664       aug_defvar_stub (xdr_in);
665       break;
666     case GUESTFS_PROC_AUG_DEFNODE:
667       aug_defnode_stub (xdr_in);
668       break;
669     case GUESTFS_PROC_AUG_GET:
670       aug_get_stub (xdr_in);
671       break;
672     case GUESTFS_PROC_AUG_SET:
673       aug_set_stub (xdr_in);
674       break;
675     case GUESTFS_PROC_AUG_INSERT:
676       aug_insert_stub (xdr_in);
677       break;
678     case GUESTFS_PROC_AUG_RM:
679       aug_rm_stub (xdr_in);
680       break;
681     case GUESTFS_PROC_AUG_MV:
682       aug_mv_stub (xdr_in);
683       break;
684     case GUESTFS_PROC_AUG_MATCH:
685       aug_match_stub (xdr_in);
686       break;
687     case GUESTFS_PROC_AUG_SAVE:
688       aug_save_stub (xdr_in);
689       break;
690     case GUESTFS_PROC_AUG_LOAD:
691       aug_load_stub (xdr_in);
692       break;
693     case GUESTFS_PROC_AUG_LS:
694       aug_ls_stub (xdr_in);
695       break;
696     default:
697       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
698   }
699 }
700
701 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";
702
703 static int lvm_tokenize_pv (char *str, struct guestfs_lvm_int_pv *r)
704 {
705   char *tok, *p, *next;
706   int i, j;
707
708   if (!str) {
709     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
710     return -1;
711   }
712   if (!*str || isspace (*str)) {
713     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
714     return -1;
715   }
716   tok = str;
717   if (!tok) {
718     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_name");
719     return -1;
720   }
721   p = strchrnul (tok, ',');
722   if (*p) next = p+1; else next = NULL;
723   *p = '\0';
724   r->pv_name = strdup (tok);
725   if (r->pv_name == NULL) {
726     perror ("strdup");
727     return -1;
728   }
729   tok = next;
730   if (!tok) {
731     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_uuid");
732     return -1;
733   }
734   p = strchrnul (tok, ',');
735   if (*p) next = p+1; else next = NULL;
736   *p = '\0';
737   for (i = j = 0; i < 32; ++j) {
738     if (tok[j] == '\0') {
739       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
740       return -1;
741     } else if (tok[j] != '-')
742       r->pv_uuid[i++] = tok[j];
743   }
744   tok = next;
745   if (!tok) {
746     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_fmt");
747     return -1;
748   }
749   p = strchrnul (tok, ',');
750   if (*p) next = p+1; else next = NULL;
751   *p = '\0';
752   r->pv_fmt = strdup (tok);
753   if (r->pv_fmt == NULL) {
754     perror ("strdup");
755     return -1;
756   }
757   tok = next;
758   if (!tok) {
759     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_size");
760     return -1;
761   }
762   p = strchrnul (tok, ',');
763   if (*p) next = p+1; else next = NULL;
764   *p = '\0';
765   if (sscanf (tok, "%"SCNu64, &r->pv_size) != 1) {
766     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_size");
767     return -1;
768   }
769   tok = next;
770   if (!tok) {
771     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "dev_size");
772     return -1;
773   }
774   p = strchrnul (tok, ',');
775   if (*p) next = p+1; else next = NULL;
776   *p = '\0';
777   if (sscanf (tok, "%"SCNu64, &r->dev_size) != 1) {
778     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "dev_size");
779     return -1;
780   }
781   tok = next;
782   if (!tok) {
783     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_free");
784     return -1;
785   }
786   p = strchrnul (tok, ',');
787   if (*p) next = p+1; else next = NULL;
788   *p = '\0';
789   if (sscanf (tok, "%"SCNu64, &r->pv_free) != 1) {
790     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_free");
791     return -1;
792   }
793   tok = next;
794   if (!tok) {
795     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_used");
796     return -1;
797   }
798   p = strchrnul (tok, ',');
799   if (*p) next = p+1; else next = NULL;
800   *p = '\0';
801   if (sscanf (tok, "%"SCNu64, &r->pv_used) != 1) {
802     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_used");
803     return -1;
804   }
805   tok = next;
806   if (!tok) {
807     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_attr");
808     return -1;
809   }
810   p = strchrnul (tok, ',');
811   if (*p) next = p+1; else next = NULL;
812   *p = '\0';
813   r->pv_attr = strdup (tok);
814   if (r->pv_attr == NULL) {
815     perror ("strdup");
816     return -1;
817   }
818   tok = next;
819   if (!tok) {
820     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_count");
821     return -1;
822   }
823   p = strchrnul (tok, ',');
824   if (*p) next = p+1; else next = NULL;
825   *p = '\0';
826   if (sscanf (tok, "%"SCNi64, &r->pv_pe_count) != 1) {
827     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_count");
828     return -1;
829   }
830   tok = next;
831   if (!tok) {
832     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_alloc_count");
833     return -1;
834   }
835   p = strchrnul (tok, ',');
836   if (*p) next = p+1; else next = NULL;
837   *p = '\0';
838   if (sscanf (tok, "%"SCNi64, &r->pv_pe_alloc_count) != 1) {
839     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_alloc_count");
840     return -1;
841   }
842   tok = next;
843   if (!tok) {
844     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_tags");
845     return -1;
846   }
847   p = strchrnul (tok, ',');
848   if (*p) next = p+1; else next = NULL;
849   *p = '\0';
850   r->pv_tags = strdup (tok);
851   if (r->pv_tags == NULL) {
852     perror ("strdup");
853     return -1;
854   }
855   tok = next;
856   if (!tok) {
857     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pe_start");
858     return -1;
859   }
860   p = strchrnul (tok, ',');
861   if (*p) next = p+1; else next = NULL;
862   *p = '\0';
863   if (sscanf (tok, "%"SCNu64, &r->pe_start) != 1) {
864     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pe_start");
865     return -1;
866   }
867   tok = next;
868   if (!tok) {
869     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_count");
870     return -1;
871   }
872   p = strchrnul (tok, ',');
873   if (*p) next = p+1; else next = NULL;
874   *p = '\0';
875   if (sscanf (tok, "%"SCNi64, &r->pv_mda_count) != 1) {
876     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_mda_count");
877     return -1;
878   }
879   tok = next;
880   if (!tok) {
881     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_free");
882     return -1;
883   }
884   p = strchrnul (tok, ',');
885   if (*p) next = p+1; else next = NULL;
886   *p = '\0';
887   if (sscanf (tok, "%"SCNu64, &r->pv_mda_free) != 1) {
888     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_mda_free");
889     return -1;
890   }
891   tok = next;
892   if (tok != NULL) {
893     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
894     return -1;
895   }
896   return 0;
897 }
898
899 guestfs_lvm_int_pv_list *
900 parse_command_line_pvs (void)
901 {
902   char *out, *err;
903   char *p, *pend;
904   int r, i;
905   guestfs_lvm_int_pv_list *ret;
906   void *newp;
907
908   ret = malloc (sizeof *ret);
909   if (!ret) {
910     reply_with_perror ("malloc");
911     return NULL;
912   }
913
914   ret->guestfs_lvm_int_pv_list_len = 0;
915   ret->guestfs_lvm_int_pv_list_val = NULL;
916
917   r = command (&out, &err,
918                "/sbin/lvm", "pvs",
919                "-o", lvm_pv_cols, "--unbuffered", "--noheadings",
920                "--nosuffix", "--separator", ",", "--units", "b", NULL);
921   if (r == -1) {
922     reply_with_error ("%s", err);
923     free (out);
924     free (err);
925     return NULL;
926   }
927
928   free (err);
929
930   /* Tokenize each line of the output. */
931   p = out;
932   i = 0;
933   while (p) {
934     pend = strchr (p, '\n');    /* Get the next line of output. */
935     if (pend) {
936       *pend = '\0';
937       pend++;
938     }
939
940     while (*p && isspace (*p))  /* Skip any leading whitespace. */
941       p++;
942
943     if (!*p) {                  /* Empty line?  Skip it. */
944       p = pend;
945       continue;
946     }
947
948     /* Allocate some space to store this next entry. */
949     newp = realloc (ret->guestfs_lvm_int_pv_list_val,
950                     sizeof (guestfs_lvm_int_pv) * (i+1));
951     if (newp == NULL) {
952       reply_with_perror ("realloc");
953       free (ret->guestfs_lvm_int_pv_list_val);
954       free (ret);
955       free (out);
956       return NULL;
957     }
958     ret->guestfs_lvm_int_pv_list_val = newp;
959
960     /* Tokenize the next entry. */
961     r = lvm_tokenize_pv (p, &ret->guestfs_lvm_int_pv_list_val[i]);
962     if (r == -1) {
963       reply_with_error ("failed to parse output of 'pvs' command");
964       free (ret->guestfs_lvm_int_pv_list_val);
965       free (ret);
966       free (out);
967       return NULL;
968     }
969
970     ++i;
971     p = pend;
972   }
973
974   ret->guestfs_lvm_int_pv_list_len = i;
975
976   free (out);
977   return ret;
978 }
979 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";
980
981 static int lvm_tokenize_vg (char *str, struct guestfs_lvm_int_vg *r)
982 {
983   char *tok, *p, *next;
984   int i, j;
985
986   if (!str) {
987     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
988     return -1;
989   }
990   if (!*str || isspace (*str)) {
991     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
992     return -1;
993   }
994   tok = str;
995   if (!tok) {
996     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_name");
997     return -1;
998   }
999   p = strchrnul (tok, ',');
1000   if (*p) next = p+1; else next = NULL;
1001   *p = '\0';
1002   r->vg_name = strdup (tok);
1003   if (r->vg_name == NULL) {
1004     perror ("strdup");
1005     return -1;
1006   }
1007   tok = next;
1008   if (!tok) {
1009     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_uuid");
1010     return -1;
1011   }
1012   p = strchrnul (tok, ',');
1013   if (*p) next = p+1; else next = NULL;
1014   *p = '\0';
1015   for (i = j = 0; i < 32; ++j) {
1016     if (tok[j] == '\0') {
1017       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1018       return -1;
1019     } else if (tok[j] != '-')
1020       r->vg_uuid[i++] = tok[j];
1021   }
1022   tok = next;
1023   if (!tok) {
1024     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_fmt");
1025     return -1;
1026   }
1027   p = strchrnul (tok, ',');
1028   if (*p) next = p+1; else next = NULL;
1029   *p = '\0';
1030   r->vg_fmt = strdup (tok);
1031   if (r->vg_fmt == NULL) {
1032     perror ("strdup");
1033     return -1;
1034   }
1035   tok = next;
1036   if (!tok) {
1037     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_attr");
1038     return -1;
1039   }
1040   p = strchrnul (tok, ',');
1041   if (*p) next = p+1; else next = NULL;
1042   *p = '\0';
1043   r->vg_attr = strdup (tok);
1044   if (r->vg_attr == NULL) {
1045     perror ("strdup");
1046     return -1;
1047   }
1048   tok = next;
1049   if (!tok) {
1050     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_size");
1051     return -1;
1052   }
1053   p = strchrnul (tok, ',');
1054   if (*p) next = p+1; else next = NULL;
1055   *p = '\0';
1056   if (sscanf (tok, "%"SCNu64, &r->vg_size) != 1) {
1057     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_size");
1058     return -1;
1059   }
1060   tok = next;
1061   if (!tok) {
1062     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free");
1063     return -1;
1064   }
1065   p = strchrnul (tok, ',');
1066   if (*p) next = p+1; else next = NULL;
1067   *p = '\0';
1068   if (sscanf (tok, "%"SCNu64, &r->vg_free) != 1) {
1069     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_free");
1070     return -1;
1071   }
1072   tok = next;
1073   if (!tok) {
1074     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_sysid");
1075     return -1;
1076   }
1077   p = strchrnul (tok, ',');
1078   if (*p) next = p+1; else next = NULL;
1079   *p = '\0';
1080   r->vg_sysid = strdup (tok);
1081   if (r->vg_sysid == NULL) {
1082     perror ("strdup");
1083     return -1;
1084   }
1085   tok = next;
1086   if (!tok) {
1087     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_size");
1088     return -1;
1089   }
1090   p = strchrnul (tok, ',');
1091   if (*p) next = p+1; else next = NULL;
1092   *p = '\0';
1093   if (sscanf (tok, "%"SCNu64, &r->vg_extent_size) != 1) {
1094     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_extent_size");
1095     return -1;
1096   }
1097   tok = next;
1098   if (!tok) {
1099     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_count");
1100     return -1;
1101   }
1102   p = strchrnul (tok, ',');
1103   if (*p) next = p+1; else next = NULL;
1104   *p = '\0';
1105   if (sscanf (tok, "%"SCNi64, &r->vg_extent_count) != 1) {
1106     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_extent_count");
1107     return -1;
1108   }
1109   tok = next;
1110   if (!tok) {
1111     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free_count");
1112     return -1;
1113   }
1114   p = strchrnul (tok, ',');
1115   if (*p) next = p+1; else next = NULL;
1116   *p = '\0';
1117   if (sscanf (tok, "%"SCNi64, &r->vg_free_count) != 1) {
1118     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_free_count");
1119     return -1;
1120   }
1121   tok = next;
1122   if (!tok) {
1123     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_lv");
1124     return -1;
1125   }
1126   p = strchrnul (tok, ',');
1127   if (*p) next = p+1; else next = NULL;
1128   *p = '\0';
1129   if (sscanf (tok, "%"SCNi64, &r->max_lv) != 1) {
1130     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_lv");
1131     return -1;
1132   }
1133   tok = next;
1134   if (!tok) {
1135     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_pv");
1136     return -1;
1137   }
1138   p = strchrnul (tok, ',');
1139   if (*p) next = p+1; else next = NULL;
1140   *p = '\0';
1141   if (sscanf (tok, "%"SCNi64, &r->max_pv) != 1) {
1142     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_pv");
1143     return -1;
1144   }
1145   tok = next;
1146   if (!tok) {
1147     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_count");
1148     return -1;
1149   }
1150   p = strchrnul (tok, ',');
1151   if (*p) next = p+1; else next = NULL;
1152   *p = '\0';
1153   if (sscanf (tok, "%"SCNi64, &r->pv_count) != 1) {
1154     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_count");
1155     return -1;
1156   }
1157   tok = next;
1158   if (!tok) {
1159     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_count");
1160     return -1;
1161   }
1162   p = strchrnul (tok, ',');
1163   if (*p) next = p+1; else next = NULL;
1164   *p = '\0';
1165   if (sscanf (tok, "%"SCNi64, &r->lv_count) != 1) {
1166     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_count");
1167     return -1;
1168   }
1169   tok = next;
1170   if (!tok) {
1171     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_count");
1172     return -1;
1173   }
1174   p = strchrnul (tok, ',');
1175   if (*p) next = p+1; else next = NULL;
1176   *p = '\0';
1177   if (sscanf (tok, "%"SCNi64, &r->snap_count) != 1) {
1178     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "snap_count");
1179     return -1;
1180   }
1181   tok = next;
1182   if (!tok) {
1183     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_seqno");
1184     return -1;
1185   }
1186   p = strchrnul (tok, ',');
1187   if (*p) next = p+1; else next = NULL;
1188   *p = '\0';
1189   if (sscanf (tok, "%"SCNi64, &r->vg_seqno) != 1) {
1190     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_seqno");
1191     return -1;
1192   }
1193   tok = next;
1194   if (!tok) {
1195     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_tags");
1196     return -1;
1197   }
1198   p = strchrnul (tok, ',');
1199   if (*p) next = p+1; else next = NULL;
1200   *p = '\0';
1201   r->vg_tags = strdup (tok);
1202   if (r->vg_tags == NULL) {
1203     perror ("strdup");
1204     return -1;
1205   }
1206   tok = next;
1207   if (!tok) {
1208     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_count");
1209     return -1;
1210   }
1211   p = strchrnul (tok, ',');
1212   if (*p) next = p+1; else next = NULL;
1213   *p = '\0';
1214   if (sscanf (tok, "%"SCNi64, &r->vg_mda_count) != 1) {
1215     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_mda_count");
1216     return -1;
1217   }
1218   tok = next;
1219   if (!tok) {
1220     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_free");
1221     return -1;
1222   }
1223   p = strchrnul (tok, ',');
1224   if (*p) next = p+1; else next = NULL;
1225   *p = '\0';
1226   if (sscanf (tok, "%"SCNu64, &r->vg_mda_free) != 1) {
1227     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_mda_free");
1228     return -1;
1229   }
1230   tok = next;
1231   if (tok != NULL) {
1232     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1233     return -1;
1234   }
1235   return 0;
1236 }
1237
1238 guestfs_lvm_int_vg_list *
1239 parse_command_line_vgs (void)
1240 {
1241   char *out, *err;
1242   char *p, *pend;
1243   int r, i;
1244   guestfs_lvm_int_vg_list *ret;
1245   void *newp;
1246
1247   ret = malloc (sizeof *ret);
1248   if (!ret) {
1249     reply_with_perror ("malloc");
1250     return NULL;
1251   }
1252
1253   ret->guestfs_lvm_int_vg_list_len = 0;
1254   ret->guestfs_lvm_int_vg_list_val = NULL;
1255
1256   r = command (&out, &err,
1257                "/sbin/lvm", "vgs",
1258                "-o", lvm_vg_cols, "--unbuffered", "--noheadings",
1259                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1260   if (r == -1) {
1261     reply_with_error ("%s", err);
1262     free (out);
1263     free (err);
1264     return NULL;
1265   }
1266
1267   free (err);
1268
1269   /* Tokenize each line of the output. */
1270   p = out;
1271   i = 0;
1272   while (p) {
1273     pend = strchr (p, '\n');    /* Get the next line of output. */
1274     if (pend) {
1275       *pend = '\0';
1276       pend++;
1277     }
1278
1279     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1280       p++;
1281
1282     if (!*p) {                  /* Empty line?  Skip it. */
1283       p = pend;
1284       continue;
1285     }
1286
1287     /* Allocate some space to store this next entry. */
1288     newp = realloc (ret->guestfs_lvm_int_vg_list_val,
1289                     sizeof (guestfs_lvm_int_vg) * (i+1));
1290     if (newp == NULL) {
1291       reply_with_perror ("realloc");
1292       free (ret->guestfs_lvm_int_vg_list_val);
1293       free (ret);
1294       free (out);
1295       return NULL;
1296     }
1297     ret->guestfs_lvm_int_vg_list_val = newp;
1298
1299     /* Tokenize the next entry. */
1300     r = lvm_tokenize_vg (p, &ret->guestfs_lvm_int_vg_list_val[i]);
1301     if (r == -1) {
1302       reply_with_error ("failed to parse output of 'vgs' command");
1303       free (ret->guestfs_lvm_int_vg_list_val);
1304       free (ret);
1305       free (out);
1306       return NULL;
1307     }
1308
1309     ++i;
1310     p = pend;
1311   }
1312
1313   ret->guestfs_lvm_int_vg_list_len = i;
1314
1315   free (out);
1316   return ret;
1317 }
1318 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";
1319
1320 static int lvm_tokenize_lv (char *str, struct guestfs_lvm_int_lv *r)
1321 {
1322   char *tok, *p, *next;
1323   int i, j;
1324
1325   if (!str) {
1326     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
1327     return -1;
1328   }
1329   if (!*str || isspace (*str)) {
1330     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
1331     return -1;
1332   }
1333   tok = str;
1334   if (!tok) {
1335     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_name");
1336     return -1;
1337   }
1338   p = strchrnul (tok, ',');
1339   if (*p) next = p+1; else next = NULL;
1340   *p = '\0';
1341   r->lv_name = strdup (tok);
1342   if (r->lv_name == NULL) {
1343     perror ("strdup");
1344     return -1;
1345   }
1346   tok = next;
1347   if (!tok) {
1348     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_uuid");
1349     return -1;
1350   }
1351   p = strchrnul (tok, ',');
1352   if (*p) next = p+1; else next = NULL;
1353   *p = '\0';
1354   for (i = j = 0; i < 32; ++j) {
1355     if (tok[j] == '\0') {
1356       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1357       return -1;
1358     } else if (tok[j] != '-')
1359       r->lv_uuid[i++] = tok[j];
1360   }
1361   tok = next;
1362   if (!tok) {
1363     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_attr");
1364     return -1;
1365   }
1366   p = strchrnul (tok, ',');
1367   if (*p) next = p+1; else next = NULL;
1368   *p = '\0';
1369   r->lv_attr = strdup (tok);
1370   if (r->lv_attr == NULL) {
1371     perror ("strdup");
1372     return -1;
1373   }
1374   tok = next;
1375   if (!tok) {
1376     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_major");
1377     return -1;
1378   }
1379   p = strchrnul (tok, ',');
1380   if (*p) next = p+1; else next = NULL;
1381   *p = '\0';
1382   if (sscanf (tok, "%"SCNi64, &r->lv_major) != 1) {
1383     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_major");
1384     return -1;
1385   }
1386   tok = next;
1387   if (!tok) {
1388     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_minor");
1389     return -1;
1390   }
1391   p = strchrnul (tok, ',');
1392   if (*p) next = p+1; else next = NULL;
1393   *p = '\0';
1394   if (sscanf (tok, "%"SCNi64, &r->lv_minor) != 1) {
1395     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_minor");
1396     return -1;
1397   }
1398   tok = next;
1399   if (!tok) {
1400     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_major");
1401     return -1;
1402   }
1403   p = strchrnul (tok, ',');
1404   if (*p) next = p+1; else next = NULL;
1405   *p = '\0';
1406   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_major) != 1) {
1407     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_major");
1408     return -1;
1409   }
1410   tok = next;
1411   if (!tok) {
1412     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_minor");
1413     return -1;
1414   }
1415   p = strchrnul (tok, ',');
1416   if (*p) next = p+1; else next = NULL;
1417   *p = '\0';
1418   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_minor) != 1) {
1419     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_minor");
1420     return -1;
1421   }
1422   tok = next;
1423   if (!tok) {
1424     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_size");
1425     return -1;
1426   }
1427   p = strchrnul (tok, ',');
1428   if (*p) next = p+1; else next = NULL;
1429   *p = '\0';
1430   if (sscanf (tok, "%"SCNu64, &r->lv_size) != 1) {
1431     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "lv_size");
1432     return -1;
1433   }
1434   tok = next;
1435   if (!tok) {
1436     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "seg_count");
1437     return -1;
1438   }
1439   p = strchrnul (tok, ',');
1440   if (*p) next = p+1; else next = NULL;
1441   *p = '\0';
1442   if (sscanf (tok, "%"SCNi64, &r->seg_count) != 1) {
1443     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "seg_count");
1444     return -1;
1445   }
1446   tok = next;
1447   if (!tok) {
1448     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "origin");
1449     return -1;
1450   }
1451   p = strchrnul (tok, ',');
1452   if (*p) next = p+1; else next = NULL;
1453   *p = '\0';
1454   r->origin = strdup (tok);
1455   if (r->origin == NULL) {
1456     perror ("strdup");
1457     return -1;
1458   }
1459   tok = next;
1460   if (!tok) {
1461     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_percent");
1462     return -1;
1463   }
1464   p = strchrnul (tok, ',');
1465   if (*p) next = p+1; else next = NULL;
1466   *p = '\0';
1467   if (tok[0] == '\0')
1468     r->snap_percent = -1;
1469   else if (sscanf (tok, "%f", &r->snap_percent) != 1) {
1470     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "snap_percent");
1471     return -1;
1472   }
1473   tok = next;
1474   if (!tok) {
1475     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "copy_percent");
1476     return -1;
1477   }
1478   p = strchrnul (tok, ',');
1479   if (*p) next = p+1; else next = NULL;
1480   *p = '\0';
1481   if (tok[0] == '\0')
1482     r->copy_percent = -1;
1483   else if (sscanf (tok, "%f", &r->copy_percent) != 1) {
1484     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "copy_percent");
1485     return -1;
1486   }
1487   tok = next;
1488   if (!tok) {
1489     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "move_pv");
1490     return -1;
1491   }
1492   p = strchrnul (tok, ',');
1493   if (*p) next = p+1; else next = NULL;
1494   *p = '\0';
1495   r->move_pv = strdup (tok);
1496   if (r->move_pv == NULL) {
1497     perror ("strdup");
1498     return -1;
1499   }
1500   tok = next;
1501   if (!tok) {
1502     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_tags");
1503     return -1;
1504   }
1505   p = strchrnul (tok, ',');
1506   if (*p) next = p+1; else next = NULL;
1507   *p = '\0';
1508   r->lv_tags = strdup (tok);
1509   if (r->lv_tags == NULL) {
1510     perror ("strdup");
1511     return -1;
1512   }
1513   tok = next;
1514   if (!tok) {
1515     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "mirror_log");
1516     return -1;
1517   }
1518   p = strchrnul (tok, ',');
1519   if (*p) next = p+1; else next = NULL;
1520   *p = '\0';
1521   r->mirror_log = strdup (tok);
1522   if (r->mirror_log == NULL) {
1523     perror ("strdup");
1524     return -1;
1525   }
1526   tok = next;
1527   if (!tok) {
1528     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "modules");
1529     return -1;
1530   }
1531   p = strchrnul (tok, ',');
1532   if (*p) next = p+1; else next = NULL;
1533   *p = '\0';
1534   r->modules = strdup (tok);
1535   if (r->modules == NULL) {
1536     perror ("strdup");
1537     return -1;
1538   }
1539   tok = next;
1540   if (tok != NULL) {
1541     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1542     return -1;
1543   }
1544   return 0;
1545 }
1546
1547 guestfs_lvm_int_lv_list *
1548 parse_command_line_lvs (void)
1549 {
1550   char *out, *err;
1551   char *p, *pend;
1552   int r, i;
1553   guestfs_lvm_int_lv_list *ret;
1554   void *newp;
1555
1556   ret = malloc (sizeof *ret);
1557   if (!ret) {
1558     reply_with_perror ("malloc");
1559     return NULL;
1560   }
1561
1562   ret->guestfs_lvm_int_lv_list_len = 0;
1563   ret->guestfs_lvm_int_lv_list_val = NULL;
1564
1565   r = command (&out, &err,
1566                "/sbin/lvm", "lvs",
1567                "-o", lvm_lv_cols, "--unbuffered", "--noheadings",
1568                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1569   if (r == -1) {
1570     reply_with_error ("%s", err);
1571     free (out);
1572     free (err);
1573     return NULL;
1574   }
1575
1576   free (err);
1577
1578   /* Tokenize each line of the output. */
1579   p = out;
1580   i = 0;
1581   while (p) {
1582     pend = strchr (p, '\n');    /* Get the next line of output. */
1583     if (pend) {
1584       *pend = '\0';
1585       pend++;
1586     }
1587
1588     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1589       p++;
1590
1591     if (!*p) {                  /* Empty line?  Skip it. */
1592       p = pend;
1593       continue;
1594     }
1595
1596     /* Allocate some space to store this next entry. */
1597     newp = realloc (ret->guestfs_lvm_int_lv_list_val,
1598                     sizeof (guestfs_lvm_int_lv) * (i+1));
1599     if (newp == NULL) {
1600       reply_with_perror ("realloc");
1601       free (ret->guestfs_lvm_int_lv_list_val);
1602       free (ret);
1603       free (out);
1604       return NULL;
1605     }
1606     ret->guestfs_lvm_int_lv_list_val = newp;
1607
1608     /* Tokenize the next entry. */
1609     r = lvm_tokenize_lv (p, &ret->guestfs_lvm_int_lv_list_val[i]);
1610     if (r == -1) {
1611       reply_with_error ("failed to parse output of 'lvs' command");
1612       free (ret->guestfs_lvm_int_lv_list_val);
1613       free (ret);
1614       free (out);
1615       return NULL;
1616     }
1617
1618     ++i;
1619     p = pend;
1620   }
1621
1622   ret->guestfs_lvm_int_lv_list_len = i;
1623
1624   free (out);
1625   return ret;
1626 }