Implement simple lvs/vgs/pvs commands.
[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 ("mount: daemon failed to decode procedure arguments");
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 ("touch: daemon failed to decode procedure arguments");
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 ("cat: daemon failed to decode procedure arguments");
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 ("ll: daemon failed to decode procedure arguments");
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 ("ls: daemon failed to decode procedure arguments");
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 void dispatch_incoming_message (XDR *xdr_in)
296 {
297   switch (proc_nr) {
298     case GUESTFS_PROC_MOUNT:
299       mount_stub (xdr_in);
300       break;
301     case GUESTFS_PROC_SYNC:
302       sync_stub (xdr_in);
303       break;
304     case GUESTFS_PROC_TOUCH:
305       touch_stub (xdr_in);
306       break;
307     case GUESTFS_PROC_CAT:
308       cat_stub (xdr_in);
309       break;
310     case GUESTFS_PROC_LL:
311       ll_stub (xdr_in);
312       break;
313     case GUESTFS_PROC_LS:
314       ls_stub (xdr_in);
315       break;
316     case GUESTFS_PROC_LIST_DEVICES:
317       list_devices_stub (xdr_in);
318       break;
319     case GUESTFS_PROC_LIST_PARTITIONS:
320       list_partitions_stub (xdr_in);
321       break;
322     case GUESTFS_PROC_PVS:
323       pvs_stub (xdr_in);
324       break;
325     case GUESTFS_PROC_VGS:
326       vgs_stub (xdr_in);
327       break;
328     case GUESTFS_PROC_LVS:
329       lvs_stub (xdr_in);
330       break;
331     case GUESTFS_PROC_PVS_FULL:
332       pvs_full_stub (xdr_in);
333       break;
334     case GUESTFS_PROC_VGS_FULL:
335       vgs_full_stub (xdr_in);
336       break;
337     case GUESTFS_PROC_LVS_FULL:
338       lvs_full_stub (xdr_in);
339       break;
340     default:
341       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
342   }
343 }
344
345 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";
346
347 static int lvm_tokenize_pv (char *str, struct guestfs_lvm_int_pv *r)
348 {
349   char *tok, *p, *next;
350   int i, j;
351
352   if (!str) {
353     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
354     return -1;
355   }
356   if (!*str || isspace (*str)) {
357     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
358     return -1;
359   }
360   tok = str;
361   if (!tok) {
362     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_name");
363     return -1;
364   }
365   p = strchrnul (tok, ',');
366   if (*p) next = p+1; else next = NULL;
367   *p = '\0';
368   r->pv_name = strdup (tok);
369   if (r->pv_name == NULL) {
370     perror ("strdup");
371     return -1;
372   }
373   tok = next;
374   if (!tok) {
375     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_uuid");
376     return -1;
377   }
378   p = strchrnul (tok, ',');
379   if (*p) next = p+1; else next = NULL;
380   *p = '\0';
381   for (i = j = 0; i < 32; ++j) {
382     if (tok[j] == '\0') {
383       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
384       return -1;
385     } else if (tok[j] != '-')
386       r->pv_uuid[i++] = tok[j];
387   }
388   tok = next;
389   if (!tok) {
390     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_fmt");
391     return -1;
392   }
393   p = strchrnul (tok, ',');
394   if (*p) next = p+1; else next = NULL;
395   *p = '\0';
396   r->pv_fmt = strdup (tok);
397   if (r->pv_fmt == NULL) {
398     perror ("strdup");
399     return -1;
400   }
401   tok = next;
402   if (!tok) {
403     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_size");
404     return -1;
405   }
406   p = strchrnul (tok, ',');
407   if (*p) next = p+1; else next = NULL;
408   *p = '\0';
409   if (sscanf (tok, "%"SCNu64, &r->pv_size) != 1) {
410     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_size");
411     return -1;
412   }
413   tok = next;
414   if (!tok) {
415     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "dev_size");
416     return -1;
417   }
418   p = strchrnul (tok, ',');
419   if (*p) next = p+1; else next = NULL;
420   *p = '\0';
421   if (sscanf (tok, "%"SCNu64, &r->dev_size) != 1) {
422     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "dev_size");
423     return -1;
424   }
425   tok = next;
426   if (!tok) {
427     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_free");
428     return -1;
429   }
430   p = strchrnul (tok, ',');
431   if (*p) next = p+1; else next = NULL;
432   *p = '\0';
433   if (sscanf (tok, "%"SCNu64, &r->pv_free) != 1) {
434     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_free");
435     return -1;
436   }
437   tok = next;
438   if (!tok) {
439     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_used");
440     return -1;
441   }
442   p = strchrnul (tok, ',');
443   if (*p) next = p+1; else next = NULL;
444   *p = '\0';
445   if (sscanf (tok, "%"SCNu64, &r->pv_used) != 1) {
446     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_used");
447     return -1;
448   }
449   tok = next;
450   if (!tok) {
451     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_attr");
452     return -1;
453   }
454   p = strchrnul (tok, ',');
455   if (*p) next = p+1; else next = NULL;
456   *p = '\0';
457   r->pv_attr = strdup (tok);
458   if (r->pv_attr == NULL) {
459     perror ("strdup");
460     return -1;
461   }
462   tok = next;
463   if (!tok) {
464     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_count");
465     return -1;
466   }
467   p = strchrnul (tok, ',');
468   if (*p) next = p+1; else next = NULL;
469   *p = '\0';
470   if (sscanf (tok, "%"SCNi64, &r->pv_pe_count) != 1) {
471     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_count");
472     return -1;
473   }
474   tok = next;
475   if (!tok) {
476     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_alloc_count");
477     return -1;
478   }
479   p = strchrnul (tok, ',');
480   if (*p) next = p+1; else next = NULL;
481   *p = '\0';
482   if (sscanf (tok, "%"SCNi64, &r->pv_pe_alloc_count) != 1) {
483     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_alloc_count");
484     return -1;
485   }
486   tok = next;
487   if (!tok) {
488     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_tags");
489     return -1;
490   }
491   p = strchrnul (tok, ',');
492   if (*p) next = p+1; else next = NULL;
493   *p = '\0';
494   r->pv_tags = strdup (tok);
495   if (r->pv_tags == NULL) {
496     perror ("strdup");
497     return -1;
498   }
499   tok = next;
500   if (!tok) {
501     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pe_start");
502     return -1;
503   }
504   p = strchrnul (tok, ',');
505   if (*p) next = p+1; else next = NULL;
506   *p = '\0';
507   if (sscanf (tok, "%"SCNu64, &r->pe_start) != 1) {
508     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pe_start");
509     return -1;
510   }
511   tok = next;
512   if (!tok) {
513     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_count");
514     return -1;
515   }
516   p = strchrnul (tok, ',');
517   if (*p) next = p+1; else next = NULL;
518   *p = '\0';
519   if (sscanf (tok, "%"SCNi64, &r->pv_mda_count) != 1) {
520     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_mda_count");
521     return -1;
522   }
523   tok = next;
524   if (!tok) {
525     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_free");
526     return -1;
527   }
528   p = strchrnul (tok, ',');
529   if (*p) next = p+1; else next = NULL;
530   *p = '\0';
531   if (sscanf (tok, "%"SCNu64, &r->pv_mda_free) != 1) {
532     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_mda_free");
533     return -1;
534   }
535   tok = next;
536   if (tok != NULL) {
537     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
538     return -1;
539   }
540   return 0;
541 }
542
543 guestfs_lvm_int_pv_list *
544 parse_command_line_pvs (void)
545 {
546   char *out, *err;
547   char *p, *pend;
548   int r, i;
549   guestfs_lvm_int_pv_list *ret;
550   void *newp;
551
552   ret = malloc (sizeof *ret);
553   if (!ret) {
554     reply_with_perror ("malloc");
555     return NULL;
556   }
557
558   ret->guestfs_lvm_int_pv_list_len = 0;
559   ret->guestfs_lvm_int_pv_list_val = NULL;
560
561   r = command (&out, &err,
562                "/sbin/lvm", "pvs",
563                "-o", lvm_pv_cols, "--unbuffered", "--noheadings",
564                "--nosuffix", "--separator", ",", "--units", "b", NULL);
565   if (r == -1) {
566     reply_with_error ("%s", err);
567     free (out);
568     free (err);
569     return NULL;
570   }
571
572   free (err);
573
574   /* Tokenize each line of the output. */
575   p = out;
576   i = 0;
577   while (p) {
578     pend = strchr (p, '\n');    /* Get the next line of output. */
579     if (pend) {
580       *pend = '\0';
581       pend++;
582     }
583
584     while (*p && isspace (*p))  /* Skip any leading whitespace. */
585       p++;
586
587     if (!*p) {                  /* Empty line?  Skip it. */
588       p = pend;
589       continue;
590     }
591
592     /* Allocate some space to store this next entry. */
593     newp = realloc (ret->guestfs_lvm_int_pv_list_val,
594                     sizeof (guestfs_lvm_int_pv) * (i+1));
595     if (newp == NULL) {
596       reply_with_perror ("realloc");
597       free (ret->guestfs_lvm_int_pv_list_val);
598       free (ret);
599       free (out);
600       return NULL;
601     }
602     ret->guestfs_lvm_int_pv_list_val = newp;
603
604     /* Tokenize the next entry. */
605     r = lvm_tokenize_pv (p, &ret->guestfs_lvm_int_pv_list_val[i]);
606     if (r == -1) {
607       reply_with_error ("failed to parse output of 'pvs' command");
608       free (ret->guestfs_lvm_int_pv_list_val);
609       free (ret);
610       free (out);
611       return NULL;
612     }
613
614     ++i;
615     p = pend;
616   }
617
618   ret->guestfs_lvm_int_pv_list_len = i;
619
620   free (out);
621   return ret;
622 }
623 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";
624
625 static int lvm_tokenize_vg (char *str, struct guestfs_lvm_int_vg *r)
626 {
627   char *tok, *p, *next;
628   int i, j;
629
630   if (!str) {
631     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
632     return -1;
633   }
634   if (!*str || isspace (*str)) {
635     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
636     return -1;
637   }
638   tok = str;
639   if (!tok) {
640     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_name");
641     return -1;
642   }
643   p = strchrnul (tok, ',');
644   if (*p) next = p+1; else next = NULL;
645   *p = '\0';
646   r->vg_name = strdup (tok);
647   if (r->vg_name == NULL) {
648     perror ("strdup");
649     return -1;
650   }
651   tok = next;
652   if (!tok) {
653     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_uuid");
654     return -1;
655   }
656   p = strchrnul (tok, ',');
657   if (*p) next = p+1; else next = NULL;
658   *p = '\0';
659   for (i = j = 0; i < 32; ++j) {
660     if (tok[j] == '\0') {
661       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
662       return -1;
663     } else if (tok[j] != '-')
664       r->vg_uuid[i++] = tok[j];
665   }
666   tok = next;
667   if (!tok) {
668     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_fmt");
669     return -1;
670   }
671   p = strchrnul (tok, ',');
672   if (*p) next = p+1; else next = NULL;
673   *p = '\0';
674   r->vg_fmt = strdup (tok);
675   if (r->vg_fmt == NULL) {
676     perror ("strdup");
677     return -1;
678   }
679   tok = next;
680   if (!tok) {
681     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_attr");
682     return -1;
683   }
684   p = strchrnul (tok, ',');
685   if (*p) next = p+1; else next = NULL;
686   *p = '\0';
687   r->vg_attr = strdup (tok);
688   if (r->vg_attr == NULL) {
689     perror ("strdup");
690     return -1;
691   }
692   tok = next;
693   if (!tok) {
694     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_size");
695     return -1;
696   }
697   p = strchrnul (tok, ',');
698   if (*p) next = p+1; else next = NULL;
699   *p = '\0';
700   if (sscanf (tok, "%"SCNu64, &r->vg_size) != 1) {
701     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_size");
702     return -1;
703   }
704   tok = next;
705   if (!tok) {
706     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free");
707     return -1;
708   }
709   p = strchrnul (tok, ',');
710   if (*p) next = p+1; else next = NULL;
711   *p = '\0';
712   if (sscanf (tok, "%"SCNu64, &r->vg_free) != 1) {
713     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_free");
714     return -1;
715   }
716   tok = next;
717   if (!tok) {
718     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_sysid");
719     return -1;
720   }
721   p = strchrnul (tok, ',');
722   if (*p) next = p+1; else next = NULL;
723   *p = '\0';
724   r->vg_sysid = strdup (tok);
725   if (r->vg_sysid == 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__, "vg_extent_size");
732     return -1;
733   }
734   p = strchrnul (tok, ',');
735   if (*p) next = p+1; else next = NULL;
736   *p = '\0';
737   if (sscanf (tok, "%"SCNu64, &r->vg_extent_size) != 1) {
738     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_extent_size");
739     return -1;
740   }
741   tok = next;
742   if (!tok) {
743     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_count");
744     return -1;
745   }
746   p = strchrnul (tok, ',');
747   if (*p) next = p+1; else next = NULL;
748   *p = '\0';
749   if (sscanf (tok, "%"SCNi64, &r->vg_extent_count) != 1) {
750     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_extent_count");
751     return -1;
752   }
753   tok = next;
754   if (!tok) {
755     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free_count");
756     return -1;
757   }
758   p = strchrnul (tok, ',');
759   if (*p) next = p+1; else next = NULL;
760   *p = '\0';
761   if (sscanf (tok, "%"SCNi64, &r->vg_free_count) != 1) {
762     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_free_count");
763     return -1;
764   }
765   tok = next;
766   if (!tok) {
767     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_lv");
768     return -1;
769   }
770   p = strchrnul (tok, ',');
771   if (*p) next = p+1; else next = NULL;
772   *p = '\0';
773   if (sscanf (tok, "%"SCNi64, &r->max_lv) != 1) {
774     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_lv");
775     return -1;
776   }
777   tok = next;
778   if (!tok) {
779     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_pv");
780     return -1;
781   }
782   p = strchrnul (tok, ',');
783   if (*p) next = p+1; else next = NULL;
784   *p = '\0';
785   if (sscanf (tok, "%"SCNi64, &r->max_pv) != 1) {
786     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_pv");
787     return -1;
788   }
789   tok = next;
790   if (!tok) {
791     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_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_count) != 1) {
798     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_count");
799     return -1;
800   }
801   tok = next;
802   if (!tok) {
803     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_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->lv_count) != 1) {
810     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_count");
811     return -1;
812   }
813   tok = next;
814   if (!tok) {
815     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_count");
816     return -1;
817   }
818   p = strchrnul (tok, ',');
819   if (*p) next = p+1; else next = NULL;
820   *p = '\0';
821   if (sscanf (tok, "%"SCNi64, &r->snap_count) != 1) {
822     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "snap_count");
823     return -1;
824   }
825   tok = next;
826   if (!tok) {
827     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_seqno");
828     return -1;
829   }
830   p = strchrnul (tok, ',');
831   if (*p) next = p+1; else next = NULL;
832   *p = '\0';
833   if (sscanf (tok, "%"SCNi64, &r->vg_seqno) != 1) {
834     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_seqno");
835     return -1;
836   }
837   tok = next;
838   if (!tok) {
839     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_tags");
840     return -1;
841   }
842   p = strchrnul (tok, ',');
843   if (*p) next = p+1; else next = NULL;
844   *p = '\0';
845   r->vg_tags = strdup (tok);
846   if (r->vg_tags == NULL) {
847     perror ("strdup");
848     return -1;
849   }
850   tok = next;
851   if (!tok) {
852     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_count");
853     return -1;
854   }
855   p = strchrnul (tok, ',');
856   if (*p) next = p+1; else next = NULL;
857   *p = '\0';
858   if (sscanf (tok, "%"SCNi64, &r->vg_mda_count) != 1) {
859     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_mda_count");
860     return -1;
861   }
862   tok = next;
863   if (!tok) {
864     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_free");
865     return -1;
866   }
867   p = strchrnul (tok, ',');
868   if (*p) next = p+1; else next = NULL;
869   *p = '\0';
870   if (sscanf (tok, "%"SCNu64, &r->vg_mda_free) != 1) {
871     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_mda_free");
872     return -1;
873   }
874   tok = next;
875   if (tok != NULL) {
876     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
877     return -1;
878   }
879   return 0;
880 }
881
882 guestfs_lvm_int_vg_list *
883 parse_command_line_vgs (void)
884 {
885   char *out, *err;
886   char *p, *pend;
887   int r, i;
888   guestfs_lvm_int_vg_list *ret;
889   void *newp;
890
891   ret = malloc (sizeof *ret);
892   if (!ret) {
893     reply_with_perror ("malloc");
894     return NULL;
895   }
896
897   ret->guestfs_lvm_int_vg_list_len = 0;
898   ret->guestfs_lvm_int_vg_list_val = NULL;
899
900   r = command (&out, &err,
901                "/sbin/lvm", "vgs",
902                "-o", lvm_vg_cols, "--unbuffered", "--noheadings",
903                "--nosuffix", "--separator", ",", "--units", "b", NULL);
904   if (r == -1) {
905     reply_with_error ("%s", err);
906     free (out);
907     free (err);
908     return NULL;
909   }
910
911   free (err);
912
913   /* Tokenize each line of the output. */
914   p = out;
915   i = 0;
916   while (p) {
917     pend = strchr (p, '\n');    /* Get the next line of output. */
918     if (pend) {
919       *pend = '\0';
920       pend++;
921     }
922
923     while (*p && isspace (*p))  /* Skip any leading whitespace. */
924       p++;
925
926     if (!*p) {                  /* Empty line?  Skip it. */
927       p = pend;
928       continue;
929     }
930
931     /* Allocate some space to store this next entry. */
932     newp = realloc (ret->guestfs_lvm_int_vg_list_val,
933                     sizeof (guestfs_lvm_int_vg) * (i+1));
934     if (newp == NULL) {
935       reply_with_perror ("realloc");
936       free (ret->guestfs_lvm_int_vg_list_val);
937       free (ret);
938       free (out);
939       return NULL;
940     }
941     ret->guestfs_lvm_int_vg_list_val = newp;
942
943     /* Tokenize the next entry. */
944     r = lvm_tokenize_vg (p, &ret->guestfs_lvm_int_vg_list_val[i]);
945     if (r == -1) {
946       reply_with_error ("failed to parse output of 'vgs' command");
947       free (ret->guestfs_lvm_int_vg_list_val);
948       free (ret);
949       free (out);
950       return NULL;
951     }
952
953     ++i;
954     p = pend;
955   }
956
957   ret->guestfs_lvm_int_vg_list_len = i;
958
959   free (out);
960   return ret;
961 }
962 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";
963
964 static int lvm_tokenize_lv (char *str, struct guestfs_lvm_int_lv *r)
965 {
966   char *tok, *p, *next;
967   int i, j;
968
969   if (!str) {
970     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
971     return -1;
972   }
973   if (!*str || isspace (*str)) {
974     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
975     return -1;
976   }
977   tok = str;
978   if (!tok) {
979     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_name");
980     return -1;
981   }
982   p = strchrnul (tok, ',');
983   if (*p) next = p+1; else next = NULL;
984   *p = '\0';
985   r->lv_name = strdup (tok);
986   if (r->lv_name == NULL) {
987     perror ("strdup");
988     return -1;
989   }
990   tok = next;
991   if (!tok) {
992     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_uuid");
993     return -1;
994   }
995   p = strchrnul (tok, ',');
996   if (*p) next = p+1; else next = NULL;
997   *p = '\0';
998   for (i = j = 0; i < 32; ++j) {
999     if (tok[j] == '\0') {
1000       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1001       return -1;
1002     } else if (tok[j] != '-')
1003       r->lv_uuid[i++] = tok[j];
1004   }
1005   tok = next;
1006   if (!tok) {
1007     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_attr");
1008     return -1;
1009   }
1010   p = strchrnul (tok, ',');
1011   if (*p) next = p+1; else next = NULL;
1012   *p = '\0';
1013   r->lv_attr = strdup (tok);
1014   if (r->lv_attr == NULL) {
1015     perror ("strdup");
1016     return -1;
1017   }
1018   tok = next;
1019   if (!tok) {
1020     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_major");
1021     return -1;
1022   }
1023   p = strchrnul (tok, ',');
1024   if (*p) next = p+1; else next = NULL;
1025   *p = '\0';
1026   if (sscanf (tok, "%"SCNi64, &r->lv_major) != 1) {
1027     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_major");
1028     return -1;
1029   }
1030   tok = next;
1031   if (!tok) {
1032     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_minor");
1033     return -1;
1034   }
1035   p = strchrnul (tok, ',');
1036   if (*p) next = p+1; else next = NULL;
1037   *p = '\0';
1038   if (sscanf (tok, "%"SCNi64, &r->lv_minor) != 1) {
1039     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_minor");
1040     return -1;
1041   }
1042   tok = next;
1043   if (!tok) {
1044     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_major");
1045     return -1;
1046   }
1047   p = strchrnul (tok, ',');
1048   if (*p) next = p+1; else next = NULL;
1049   *p = '\0';
1050   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_major) != 1) {
1051     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_major");
1052     return -1;
1053   }
1054   tok = next;
1055   if (!tok) {
1056     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_minor");
1057     return -1;
1058   }
1059   p = strchrnul (tok, ',');
1060   if (*p) next = p+1; else next = NULL;
1061   *p = '\0';
1062   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_minor) != 1) {
1063     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_minor");
1064     return -1;
1065   }
1066   tok = next;
1067   if (!tok) {
1068     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_size");
1069     return -1;
1070   }
1071   p = strchrnul (tok, ',');
1072   if (*p) next = p+1; else next = NULL;
1073   *p = '\0';
1074   if (sscanf (tok, "%"SCNu64, &r->lv_size) != 1) {
1075     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "lv_size");
1076     return -1;
1077   }
1078   tok = next;
1079   if (!tok) {
1080     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "seg_count");
1081     return -1;
1082   }
1083   p = strchrnul (tok, ',');
1084   if (*p) next = p+1; else next = NULL;
1085   *p = '\0';
1086   if (sscanf (tok, "%"SCNi64, &r->seg_count) != 1) {
1087     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "seg_count");
1088     return -1;
1089   }
1090   tok = next;
1091   if (!tok) {
1092     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "origin");
1093     return -1;
1094   }
1095   p = strchrnul (tok, ',');
1096   if (*p) next = p+1; else next = NULL;
1097   *p = '\0';
1098   r->origin = strdup (tok);
1099   if (r->origin == NULL) {
1100     perror ("strdup");
1101     return -1;
1102   }
1103   tok = next;
1104   if (!tok) {
1105     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_percent");
1106     return -1;
1107   }
1108   p = strchrnul (tok, ',');
1109   if (*p) next = p+1; else next = NULL;
1110   *p = '\0';
1111   if (tok[0] == '\0')
1112     r->snap_percent = -1;
1113   else if (sscanf (tok, "%f", &r->snap_percent) != 1) {
1114     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "snap_percent");
1115     return -1;
1116   }
1117   tok = next;
1118   if (!tok) {
1119     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "copy_percent");
1120     return -1;
1121   }
1122   p = strchrnul (tok, ',');
1123   if (*p) next = p+1; else next = NULL;
1124   *p = '\0';
1125   if (tok[0] == '\0')
1126     r->copy_percent = -1;
1127   else if (sscanf (tok, "%f", &r->copy_percent) != 1) {
1128     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "copy_percent");
1129     return -1;
1130   }
1131   tok = next;
1132   if (!tok) {
1133     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "move_pv");
1134     return -1;
1135   }
1136   p = strchrnul (tok, ',');
1137   if (*p) next = p+1; else next = NULL;
1138   *p = '\0';
1139   r->move_pv = strdup (tok);
1140   if (r->move_pv == NULL) {
1141     perror ("strdup");
1142     return -1;
1143   }
1144   tok = next;
1145   if (!tok) {
1146     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_tags");
1147     return -1;
1148   }
1149   p = strchrnul (tok, ',');
1150   if (*p) next = p+1; else next = NULL;
1151   *p = '\0';
1152   r->lv_tags = strdup (tok);
1153   if (r->lv_tags == NULL) {
1154     perror ("strdup");
1155     return -1;
1156   }
1157   tok = next;
1158   if (!tok) {
1159     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "mirror_log");
1160     return -1;
1161   }
1162   p = strchrnul (tok, ',');
1163   if (*p) next = p+1; else next = NULL;
1164   *p = '\0';
1165   r->mirror_log = strdup (tok);
1166   if (r->mirror_log == NULL) {
1167     perror ("strdup");
1168     return -1;
1169   }
1170   tok = next;
1171   if (!tok) {
1172     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "modules");
1173     return -1;
1174   }
1175   p = strchrnul (tok, ',');
1176   if (*p) next = p+1; else next = NULL;
1177   *p = '\0';
1178   r->modules = strdup (tok);
1179   if (r->modules == NULL) {
1180     perror ("strdup");
1181     return -1;
1182   }
1183   tok = next;
1184   if (tok != NULL) {
1185     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1186     return -1;
1187   }
1188   return 0;
1189 }
1190
1191 guestfs_lvm_int_lv_list *
1192 parse_command_line_lvs (void)
1193 {
1194   char *out, *err;
1195   char *p, *pend;
1196   int r, i;
1197   guestfs_lvm_int_lv_list *ret;
1198   void *newp;
1199
1200   ret = malloc (sizeof *ret);
1201   if (!ret) {
1202     reply_with_perror ("malloc");
1203     return NULL;
1204   }
1205
1206   ret->guestfs_lvm_int_lv_list_len = 0;
1207   ret->guestfs_lvm_int_lv_list_val = NULL;
1208
1209   r = command (&out, &err,
1210                "/sbin/lvm", "lvs",
1211                "-o", lvm_lv_cols, "--unbuffered", "--noheadings",
1212                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1213   if (r == -1) {
1214     reply_with_error ("%s", err);
1215     free (out);
1216     free (err);
1217     return NULL;
1218   }
1219
1220   free (err);
1221
1222   /* Tokenize each line of the output. */
1223   p = out;
1224   i = 0;
1225   while (p) {
1226     pend = strchr (p, '\n');    /* Get the next line of output. */
1227     if (pend) {
1228       *pend = '\0';
1229       pend++;
1230     }
1231
1232     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1233       p++;
1234
1235     if (!*p) {                  /* Empty line?  Skip it. */
1236       p = pend;
1237       continue;
1238     }
1239
1240     /* Allocate some space to store this next entry. */
1241     newp = realloc (ret->guestfs_lvm_int_lv_list_val,
1242                     sizeof (guestfs_lvm_int_lv) * (i+1));
1243     if (newp == NULL) {
1244       reply_with_perror ("realloc");
1245       free (ret->guestfs_lvm_int_lv_list_val);
1246       free (ret);
1247       free (out);
1248       return NULL;
1249     }
1250     ret->guestfs_lvm_int_lv_list_val = newp;
1251
1252     /* Tokenize the next entry. */
1253     r = lvm_tokenize_lv (p, &ret->guestfs_lvm_int_lv_list_val[i]);
1254     if (r == -1) {
1255       reply_with_error ("failed to parse output of 'lvs' command");
1256       free (ret->guestfs_lvm_int_lv_list_val);
1257       free (ret);
1258       free (out);
1259       return NULL;
1260     }
1261
1262     ++i;
1263     p = pend;
1264   }
1265
1266   ret->guestfs_lvm_int_lv_list_len = i;
1267
1268   free (out);
1269   return ret;
1270 }