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