Fix 'file(1)' command to work on /dev devices.
[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 */
55     goto done;
56
57   reply (NULL, NULL);
58 done:
59   xdr_free ((xdrproc_t) xdr_guestfs_mount_args, (char *) &args);
60 }
61
62 static void sync_stub (XDR *xdr_in)
63 {
64   int r;
65
66   r = do_sync ();
67   if (r == -1)
68     /* do_sync has already called reply_with_error */
69     goto done;
70
71   reply (NULL, NULL);
72 done: ;
73 }
74
75 static void touch_stub (XDR *xdr_in)
76 {
77   int r;
78   struct guestfs_touch_args args;
79   const char *path;
80
81   memset (&args, 0, sizeof args);
82
83   if (!xdr_guestfs_touch_args (xdr_in, &args)) {
84     reply_with_error ("%s: daemon failed to decode procedure arguments", "touch");
85     return;
86   }
87   path = args.path;
88
89   r = do_touch (path);
90   if (r == -1)
91     /* do_touch has already called reply_with_error */
92     goto done;
93
94   reply (NULL, NULL);
95 done:
96   xdr_free ((xdrproc_t) xdr_guestfs_touch_args, (char *) &args);
97 }
98
99 static void cat_stub (XDR *xdr_in)
100 {
101   char *r;
102   struct guestfs_cat_args args;
103   const char *path;
104
105   memset (&args, 0, sizeof args);
106
107   if (!xdr_guestfs_cat_args (xdr_in, &args)) {
108     reply_with_error ("%s: daemon failed to decode procedure arguments", "cat");
109     return;
110   }
111   path = args.path;
112
113   r = do_cat (path);
114   if (r == NULL)
115     /* do_cat has already called reply_with_error */
116     goto done;
117
118   struct guestfs_cat_ret ret;
119   ret.content = r;
120   reply ((xdrproc_t) &xdr_guestfs_cat_ret, (char *) &ret);
121   free (r);
122 done:
123   xdr_free ((xdrproc_t) xdr_guestfs_cat_args, (char *) &args);
124 }
125
126 static void ll_stub (XDR *xdr_in)
127 {
128   char *r;
129   struct guestfs_ll_args args;
130   const char *directory;
131
132   memset (&args, 0, sizeof args);
133
134   if (!xdr_guestfs_ll_args (xdr_in, &args)) {
135     reply_with_error ("%s: daemon failed to decode procedure arguments", "ll");
136     return;
137   }
138   directory = args.directory;
139
140   r = do_ll (directory);
141   if (r == NULL)
142     /* do_ll has already called reply_with_error */
143     goto done;
144
145   struct guestfs_ll_ret ret;
146   ret.listing = r;
147   reply ((xdrproc_t) &xdr_guestfs_ll_ret, (char *) &ret);
148   free (r);
149 done:
150   xdr_free ((xdrproc_t) xdr_guestfs_ll_args, (char *) &args);
151 }
152
153 static void ls_stub (XDR *xdr_in)
154 {
155   char **r;
156   struct guestfs_ls_args args;
157   const char *directory;
158
159   memset (&args, 0, sizeof args);
160
161   if (!xdr_guestfs_ls_args (xdr_in, &args)) {
162     reply_with_error ("%s: daemon failed to decode procedure arguments", "ls");
163     return;
164   }
165   directory = args.directory;
166
167   r = do_ls (directory);
168   if (r == NULL)
169     /* do_ls has already called reply_with_error */
170     goto done;
171
172   struct guestfs_ls_ret ret;
173   ret.listing.listing_len = count_strings (r);
174   ret.listing.listing_val = r;
175   reply ((xdrproc_t) &xdr_guestfs_ls_ret, (char *) &ret);
176   free_strings (r);
177 done:
178   xdr_free ((xdrproc_t) xdr_guestfs_ls_args, (char *) &args);
179 }
180
181 static void list_devices_stub (XDR *xdr_in)
182 {
183   char **r;
184
185   r = do_list_devices ();
186   if (r == NULL)
187     /* do_list_devices has already called reply_with_error */
188     goto done;
189
190   struct guestfs_list_devices_ret ret;
191   ret.devices.devices_len = count_strings (r);
192   ret.devices.devices_val = r;
193   reply ((xdrproc_t) &xdr_guestfs_list_devices_ret, (char *) &ret);
194   free_strings (r);
195 done: ;
196 }
197
198 static void list_partitions_stub (XDR *xdr_in)
199 {
200   char **r;
201
202   r = do_list_partitions ();
203   if (r == NULL)
204     /* do_list_partitions has already called reply_with_error */
205     goto done;
206
207   struct guestfs_list_partitions_ret ret;
208   ret.partitions.partitions_len = count_strings (r);
209   ret.partitions.partitions_val = r;
210   reply ((xdrproc_t) &xdr_guestfs_list_partitions_ret, (char *) &ret);
211   free_strings (r);
212 done: ;
213 }
214
215 static void pvs_stub (XDR *xdr_in)
216 {
217   char **r;
218
219   r = do_pvs ();
220   if (r == NULL)
221     /* do_pvs has already called reply_with_error */
222     goto done;
223
224   struct guestfs_pvs_ret ret;
225   ret.physvols.physvols_len = count_strings (r);
226   ret.physvols.physvols_val = r;
227   reply ((xdrproc_t) &xdr_guestfs_pvs_ret, (char *) &ret);
228   free_strings (r);
229 done: ;
230 }
231
232 static void vgs_stub (XDR *xdr_in)
233 {
234   char **r;
235
236   r = do_vgs ();
237   if (r == NULL)
238     /* do_vgs has already called reply_with_error */
239     goto done;
240
241   struct guestfs_vgs_ret ret;
242   ret.volgroups.volgroups_len = count_strings (r);
243   ret.volgroups.volgroups_val = r;
244   reply ((xdrproc_t) &xdr_guestfs_vgs_ret, (char *) &ret);
245   free_strings (r);
246 done: ;
247 }
248
249 static void lvs_stub (XDR *xdr_in)
250 {
251   char **r;
252
253   r = do_lvs ();
254   if (r == NULL)
255     /* do_lvs has already called reply_with_error */
256     goto done;
257
258   struct guestfs_lvs_ret ret;
259   ret.logvols.logvols_len = count_strings (r);
260   ret.logvols.logvols_val = r;
261   reply ((xdrproc_t) &xdr_guestfs_lvs_ret, (char *) &ret);
262   free_strings (r);
263 done: ;
264 }
265
266 static void pvs_full_stub (XDR *xdr_in)
267 {
268   guestfs_lvm_int_pv_list *r;
269
270   r = do_pvs_full ();
271   if (r == NULL)
272     /* do_pvs_full has already called reply_with_error */
273     goto done;
274
275   struct guestfs_pvs_full_ret ret;
276   ret.physvols = *r;
277   reply ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
278   xdr_free ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret);
279 done: ;
280 }
281
282 static void vgs_full_stub (XDR *xdr_in)
283 {
284   guestfs_lvm_int_vg_list *r;
285
286   r = do_vgs_full ();
287   if (r == NULL)
288     /* do_vgs_full has already called reply_with_error */
289     goto done;
290
291   struct guestfs_vgs_full_ret ret;
292   ret.volgroups = *r;
293   reply ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
294   xdr_free ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret);
295 done: ;
296 }
297
298 static void lvs_full_stub (XDR *xdr_in)
299 {
300   guestfs_lvm_int_lv_list *r;
301
302   r = do_lvs_full ();
303   if (r == NULL)
304     /* do_lvs_full has already called reply_with_error */
305     goto done;
306
307   struct guestfs_lvs_full_ret ret;
308   ret.logvols = *r;
309   reply ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
310   xdr_free ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret);
311 done: ;
312 }
313
314 static void read_lines_stub (XDR *xdr_in)
315 {
316   char **r;
317   struct guestfs_read_lines_args args;
318   const char *path;
319
320   memset (&args, 0, sizeof args);
321
322   if (!xdr_guestfs_read_lines_args (xdr_in, &args)) {
323     reply_with_error ("%s: daemon failed to decode procedure arguments", "read_lines");
324     return;
325   }
326   path = args.path;
327
328   r = do_read_lines (path);
329   if (r == NULL)
330     /* do_read_lines has already called reply_with_error */
331     goto done;
332
333   struct guestfs_read_lines_ret ret;
334   ret.lines.lines_len = count_strings (r);
335   ret.lines.lines_val = r;
336   reply ((xdrproc_t) &xdr_guestfs_read_lines_ret, (char *) &ret);
337   free_strings (r);
338 done:
339   xdr_free ((xdrproc_t) xdr_guestfs_read_lines_args, (char *) &args);
340 }
341
342 static void aug_init_stub (XDR *xdr_in)
343 {
344   int r;
345   struct guestfs_aug_init_args args;
346   const char *root;
347   int flags;
348
349   memset (&args, 0, sizeof args);
350
351   if (!xdr_guestfs_aug_init_args (xdr_in, &args)) {
352     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_init");
353     return;
354   }
355   root = args.root;
356   flags = args.flags;
357
358   r = do_aug_init (root, flags);
359   if (r == -1)
360     /* do_aug_init has already called reply_with_error */
361     goto done;
362
363   reply (NULL, NULL);
364 done:
365   xdr_free ((xdrproc_t) xdr_guestfs_aug_init_args, (char *) &args);
366 }
367
368 static void aug_close_stub (XDR *xdr_in)
369 {
370   int r;
371
372   r = do_aug_close ();
373   if (r == -1)
374     /* do_aug_close has already called reply_with_error */
375     goto done;
376
377   reply (NULL, NULL);
378 done: ;
379 }
380
381 static void aug_defvar_stub (XDR *xdr_in)
382 {
383   int r;
384   struct guestfs_aug_defvar_args args;
385   const char *name;
386   const char *expr;
387
388   memset (&args, 0, sizeof args);
389
390   if (!xdr_guestfs_aug_defvar_args (xdr_in, &args)) {
391     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defvar");
392     return;
393   }
394   name = args.name;
395   expr = args.expr ? *args.expr : NULL;
396
397   r = do_aug_defvar (name, expr);
398   if (r == -1)
399     /* do_aug_defvar has already called reply_with_error */
400     goto done;
401
402   struct guestfs_aug_defvar_ret ret;
403   ret.nrnodes = r;
404   reply ((xdrproc_t) &xdr_guestfs_aug_defvar_ret, (char *) &ret);
405 done:
406   xdr_free ((xdrproc_t) xdr_guestfs_aug_defvar_args, (char *) &args);
407 }
408
409 static void aug_defnode_stub (XDR *xdr_in)
410 {
411   guestfs_aug_defnode_ret *r;
412   struct guestfs_aug_defnode_args args;
413   const char *name;
414   const char *expr;
415   const char *val;
416
417   memset (&args, 0, sizeof args);
418
419   if (!xdr_guestfs_aug_defnode_args (xdr_in, &args)) {
420     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_defnode");
421     return;
422   }
423   name = args.name;
424   expr = args.expr;
425   val = args.val;
426
427   r = do_aug_defnode (name, expr, val);
428   if (r == NULL)
429     /* do_aug_defnode has already called reply_with_error */
430     goto done;
431
432   reply ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
433   xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r);
434 done:
435   xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_args, (char *) &args);
436 }
437
438 static void aug_get_stub (XDR *xdr_in)
439 {
440   char *r;
441   struct guestfs_aug_get_args args;
442   const char *path;
443
444   memset (&args, 0, sizeof args);
445
446   if (!xdr_guestfs_aug_get_args (xdr_in, &args)) {
447     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_get");
448     return;
449   }
450   path = args.path;
451
452   r = do_aug_get (path);
453   if (r == NULL)
454     /* do_aug_get has already called reply_with_error */
455     goto done;
456
457   struct guestfs_aug_get_ret ret;
458   ret.val = r;
459   reply ((xdrproc_t) &xdr_guestfs_aug_get_ret, (char *) &ret);
460   free (r);
461 done:
462   xdr_free ((xdrproc_t) xdr_guestfs_aug_get_args, (char *) &args);
463 }
464
465 static void aug_set_stub (XDR *xdr_in)
466 {
467   int r;
468   struct guestfs_aug_set_args args;
469   const char *path;
470   const char *val;
471
472   memset (&args, 0, sizeof args);
473
474   if (!xdr_guestfs_aug_set_args (xdr_in, &args)) {
475     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_set");
476     return;
477   }
478   path = args.path;
479   val = args.val;
480
481   r = do_aug_set (path, val);
482   if (r == -1)
483     /* do_aug_set has already called reply_with_error */
484     goto done;
485
486   reply (NULL, NULL);
487 done:
488   xdr_free ((xdrproc_t) xdr_guestfs_aug_set_args, (char *) &args);
489 }
490
491 static void aug_insert_stub (XDR *xdr_in)
492 {
493   int r;
494   struct guestfs_aug_insert_args args;
495   const char *path;
496   const char *label;
497   int before;
498
499   memset (&args, 0, sizeof args);
500
501   if (!xdr_guestfs_aug_insert_args (xdr_in, &args)) {
502     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_insert");
503     return;
504   }
505   path = args.path;
506   label = args.label;
507   before = args.before;
508
509   r = do_aug_insert (path, label, before);
510   if (r == -1)
511     /* do_aug_insert has already called reply_with_error */
512     goto done;
513
514   reply (NULL, NULL);
515 done:
516   xdr_free ((xdrproc_t) xdr_guestfs_aug_insert_args, (char *) &args);
517 }
518
519 static void aug_rm_stub (XDR *xdr_in)
520 {
521   int r;
522   struct guestfs_aug_rm_args args;
523   const char *path;
524
525   memset (&args, 0, sizeof args);
526
527   if (!xdr_guestfs_aug_rm_args (xdr_in, &args)) {
528     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_rm");
529     return;
530   }
531   path = args.path;
532
533   r = do_aug_rm (path);
534   if (r == -1)
535     /* do_aug_rm has already called reply_with_error */
536     goto done;
537
538   struct guestfs_aug_rm_ret ret;
539   ret.nrnodes = r;
540   reply ((xdrproc_t) &xdr_guestfs_aug_rm_ret, (char *) &ret);
541 done:
542   xdr_free ((xdrproc_t) xdr_guestfs_aug_rm_args, (char *) &args);
543 }
544
545 static void aug_mv_stub (XDR *xdr_in)
546 {
547   int r;
548   struct guestfs_aug_mv_args args;
549   const char *src;
550   const char *dest;
551
552   memset (&args, 0, sizeof args);
553
554   if (!xdr_guestfs_aug_mv_args (xdr_in, &args)) {
555     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_mv");
556     return;
557   }
558   src = args.src;
559   dest = args.dest;
560
561   r = do_aug_mv (src, dest);
562   if (r == -1)
563     /* do_aug_mv has already called reply_with_error */
564     goto done;
565
566   reply (NULL, NULL);
567 done:
568   xdr_free ((xdrproc_t) xdr_guestfs_aug_mv_args, (char *) &args);
569 }
570
571 static void aug_match_stub (XDR *xdr_in)
572 {
573   char **r;
574   struct guestfs_aug_match_args args;
575   const char *path;
576
577   memset (&args, 0, sizeof args);
578
579   if (!xdr_guestfs_aug_match_args (xdr_in, &args)) {
580     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_match");
581     return;
582   }
583   path = args.path;
584
585   r = do_aug_match (path);
586   if (r == NULL)
587     /* do_aug_match has already called reply_with_error */
588     goto done;
589
590   struct guestfs_aug_match_ret ret;
591   ret.matches.matches_len = count_strings (r);
592   ret.matches.matches_val = r;
593   reply ((xdrproc_t) &xdr_guestfs_aug_match_ret, (char *) &ret);
594   free_strings (r);
595 done:
596   xdr_free ((xdrproc_t) xdr_guestfs_aug_match_args, (char *) &args);
597 }
598
599 static void aug_save_stub (XDR *xdr_in)
600 {
601   int r;
602
603   r = do_aug_save ();
604   if (r == -1)
605     /* do_aug_save has already called reply_with_error */
606     goto done;
607
608   reply (NULL, NULL);
609 done: ;
610 }
611
612 static void aug_load_stub (XDR *xdr_in)
613 {
614   int r;
615
616   r = do_aug_load ();
617   if (r == -1)
618     /* do_aug_load has already called reply_with_error */
619     goto done;
620
621   reply (NULL, NULL);
622 done: ;
623 }
624
625 static void aug_ls_stub (XDR *xdr_in)
626 {
627   char **r;
628   struct guestfs_aug_ls_args args;
629   const char *path;
630
631   memset (&args, 0, sizeof args);
632
633   if (!xdr_guestfs_aug_ls_args (xdr_in, &args)) {
634     reply_with_error ("%s: daemon failed to decode procedure arguments", "aug_ls");
635     return;
636   }
637   path = args.path;
638
639   r = do_aug_ls (path);
640   if (r == NULL)
641     /* do_aug_ls has already called reply_with_error */
642     goto done;
643
644   struct guestfs_aug_ls_ret ret;
645   ret.matches.matches_len = count_strings (r);
646   ret.matches.matches_val = r;
647   reply ((xdrproc_t) &xdr_guestfs_aug_ls_ret, (char *) &ret);
648   free_strings (r);
649 done:
650   xdr_free ((xdrproc_t) xdr_guestfs_aug_ls_args, (char *) &args);
651 }
652
653 static void rm_stub (XDR *xdr_in)
654 {
655   int r;
656   struct guestfs_rm_args args;
657   const char *path;
658
659   memset (&args, 0, sizeof args);
660
661   if (!xdr_guestfs_rm_args (xdr_in, &args)) {
662     reply_with_error ("%s: daemon failed to decode procedure arguments", "rm");
663     return;
664   }
665   path = args.path;
666
667   r = do_rm (path);
668   if (r == -1)
669     /* do_rm has already called reply_with_error */
670     goto done;
671
672   reply (NULL, NULL);
673 done:
674   xdr_free ((xdrproc_t) xdr_guestfs_rm_args, (char *) &args);
675 }
676
677 static void rmdir_stub (XDR *xdr_in)
678 {
679   int r;
680   struct guestfs_rmdir_args args;
681   const char *path;
682
683   memset (&args, 0, sizeof args);
684
685   if (!xdr_guestfs_rmdir_args (xdr_in, &args)) {
686     reply_with_error ("%s: daemon failed to decode procedure arguments", "rmdir");
687     return;
688   }
689   path = args.path;
690
691   r = do_rmdir (path);
692   if (r == -1)
693     /* do_rmdir has already called reply_with_error */
694     goto done;
695
696   reply (NULL, NULL);
697 done:
698   xdr_free ((xdrproc_t) xdr_guestfs_rmdir_args, (char *) &args);
699 }
700
701 static void rm_rf_stub (XDR *xdr_in)
702 {
703   int r;
704   struct guestfs_rm_rf_args args;
705   const char *path;
706
707   memset (&args, 0, sizeof args);
708
709   if (!xdr_guestfs_rm_rf_args (xdr_in, &args)) {
710     reply_with_error ("%s: daemon failed to decode procedure arguments", "rm_rf");
711     return;
712   }
713   path = args.path;
714
715   r = do_rm_rf (path);
716   if (r == -1)
717     /* do_rm_rf has already called reply_with_error */
718     goto done;
719
720   reply (NULL, NULL);
721 done:
722   xdr_free ((xdrproc_t) xdr_guestfs_rm_rf_args, (char *) &args);
723 }
724
725 static void mkdir_stub (XDR *xdr_in)
726 {
727   int r;
728   struct guestfs_mkdir_args args;
729   const char *path;
730
731   memset (&args, 0, sizeof args);
732
733   if (!xdr_guestfs_mkdir_args (xdr_in, &args)) {
734     reply_with_error ("%s: daemon failed to decode procedure arguments", "mkdir");
735     return;
736   }
737   path = args.path;
738
739   r = do_mkdir (path);
740   if (r == -1)
741     /* do_mkdir has already called reply_with_error */
742     goto done;
743
744   reply (NULL, NULL);
745 done:
746   xdr_free ((xdrproc_t) xdr_guestfs_mkdir_args, (char *) &args);
747 }
748
749 static void mkdir_p_stub (XDR *xdr_in)
750 {
751   int r;
752   struct guestfs_mkdir_p_args args;
753   const char *path;
754
755   memset (&args, 0, sizeof args);
756
757   if (!xdr_guestfs_mkdir_p_args (xdr_in, &args)) {
758     reply_with_error ("%s: daemon failed to decode procedure arguments", "mkdir_p");
759     return;
760   }
761   path = args.path;
762
763   r = do_mkdir_p (path);
764   if (r == -1)
765     /* do_mkdir_p has already called reply_with_error */
766     goto done;
767
768   reply (NULL, NULL);
769 done:
770   xdr_free ((xdrproc_t) xdr_guestfs_mkdir_p_args, (char *) &args);
771 }
772
773 static void chmod_stub (XDR *xdr_in)
774 {
775   int r;
776   struct guestfs_chmod_args args;
777   int mode;
778   const char *path;
779
780   memset (&args, 0, sizeof args);
781
782   if (!xdr_guestfs_chmod_args (xdr_in, &args)) {
783     reply_with_error ("%s: daemon failed to decode procedure arguments", "chmod");
784     return;
785   }
786   mode = args.mode;
787   path = args.path;
788
789   r = do_chmod (mode, path);
790   if (r == -1)
791     /* do_chmod has already called reply_with_error */
792     goto done;
793
794   reply (NULL, NULL);
795 done:
796   xdr_free ((xdrproc_t) xdr_guestfs_chmod_args, (char *) &args);
797 }
798
799 static void chown_stub (XDR *xdr_in)
800 {
801   int r;
802   struct guestfs_chown_args args;
803   int owner;
804   int group;
805   const char *path;
806
807   memset (&args, 0, sizeof args);
808
809   if (!xdr_guestfs_chown_args (xdr_in, &args)) {
810     reply_with_error ("%s: daemon failed to decode procedure arguments", "chown");
811     return;
812   }
813   owner = args.owner;
814   group = args.group;
815   path = args.path;
816
817   r = do_chown (owner, group, path);
818   if (r == -1)
819     /* do_chown has already called reply_with_error */
820     goto done;
821
822   reply (NULL, NULL);
823 done:
824   xdr_free ((xdrproc_t) xdr_guestfs_chown_args, (char *) &args);
825 }
826
827 static void exists_stub (XDR *xdr_in)
828 {
829   int r;
830   struct guestfs_exists_args args;
831   const char *path;
832
833   memset (&args, 0, sizeof args);
834
835   if (!xdr_guestfs_exists_args (xdr_in, &args)) {
836     reply_with_error ("%s: daemon failed to decode procedure arguments", "exists");
837     return;
838   }
839   path = args.path;
840
841   r = do_exists (path);
842   if (r == -1)
843     /* do_exists has already called reply_with_error */
844     goto done;
845
846   struct guestfs_exists_ret ret;
847   ret.existsflag = r;
848   reply ((xdrproc_t) &xdr_guestfs_exists_ret, (char *) &ret);
849 done:
850   xdr_free ((xdrproc_t) xdr_guestfs_exists_args, (char *) &args);
851 }
852
853 static void is_file_stub (XDR *xdr_in)
854 {
855   int r;
856   struct guestfs_is_file_args args;
857   const char *path;
858
859   memset (&args, 0, sizeof args);
860
861   if (!xdr_guestfs_is_file_args (xdr_in, &args)) {
862     reply_with_error ("%s: daemon failed to decode procedure arguments", "is_file");
863     return;
864   }
865   path = args.path;
866
867   r = do_is_file (path);
868   if (r == -1)
869     /* do_is_file has already called reply_with_error */
870     goto done;
871
872   struct guestfs_is_file_ret ret;
873   ret.fileflag = r;
874   reply ((xdrproc_t) &xdr_guestfs_is_file_ret, (char *) &ret);
875 done:
876   xdr_free ((xdrproc_t) xdr_guestfs_is_file_args, (char *) &args);
877 }
878
879 static void is_dir_stub (XDR *xdr_in)
880 {
881   int r;
882   struct guestfs_is_dir_args args;
883   const char *path;
884
885   memset (&args, 0, sizeof args);
886
887   if (!xdr_guestfs_is_dir_args (xdr_in, &args)) {
888     reply_with_error ("%s: daemon failed to decode procedure arguments", "is_dir");
889     return;
890   }
891   path = args.path;
892
893   r = do_is_dir (path);
894   if (r == -1)
895     /* do_is_dir has already called reply_with_error */
896     goto done;
897
898   struct guestfs_is_dir_ret ret;
899   ret.dirflag = r;
900   reply ((xdrproc_t) &xdr_guestfs_is_dir_ret, (char *) &ret);
901 done:
902   xdr_free ((xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args);
903 }
904
905 static void pvcreate_stub (XDR *xdr_in)
906 {
907   int r;
908   struct guestfs_pvcreate_args args;
909   const char *device;
910
911   memset (&args, 0, sizeof args);
912
913   if (!xdr_guestfs_pvcreate_args (xdr_in, &args)) {
914     reply_with_error ("%s: daemon failed to decode procedure arguments", "pvcreate");
915     return;
916   }
917   device = args.device;
918
919   r = do_pvcreate (device);
920   if (r == -1)
921     /* do_pvcreate has already called reply_with_error */
922     goto done;
923
924   reply (NULL, NULL);
925 done:
926   xdr_free ((xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args);
927 }
928
929 static void vgcreate_stub (XDR *xdr_in)
930 {
931   int r;
932   struct guestfs_vgcreate_args args;
933   const char *volgroup;
934   char **physvols;
935
936   memset (&args, 0, sizeof args);
937
938   if (!xdr_guestfs_vgcreate_args (xdr_in, &args)) {
939     reply_with_error ("%s: daemon failed to decode procedure arguments", "vgcreate");
940     return;
941   }
942   volgroup = args.volgroup;
943   args.physvols.physvols_val = realloc (args.physvols.physvols_val, sizeof (char *) * (args.physvols.physvols_len+1));
944   args.physvols.physvols_val[args.physvols.physvols_len] = NULL;
945   physvols = args.physvols.physvols_val;
946
947   r = do_vgcreate (volgroup, physvols);
948   if (r == -1)
949     /* do_vgcreate has already called reply_with_error */
950     goto done;
951
952   reply (NULL, NULL);
953 done:
954   xdr_free ((xdrproc_t) xdr_guestfs_vgcreate_args, (char *) &args);
955 }
956
957 static void lvcreate_stub (XDR *xdr_in)
958 {
959   int r;
960   struct guestfs_lvcreate_args args;
961   const char *logvol;
962   const char *volgroup;
963   int mbytes;
964
965   memset (&args, 0, sizeof args);
966
967   if (!xdr_guestfs_lvcreate_args (xdr_in, &args)) {
968     reply_with_error ("%s: daemon failed to decode procedure arguments", "lvcreate");
969     return;
970   }
971   logvol = args.logvol;
972   volgroup = args.volgroup;
973   mbytes = args.mbytes;
974
975   r = do_lvcreate (logvol, volgroup, mbytes);
976   if (r == -1)
977     /* do_lvcreate has already called reply_with_error */
978     goto done;
979
980   reply (NULL, NULL);
981 done:
982   xdr_free ((xdrproc_t) xdr_guestfs_lvcreate_args, (char *) &args);
983 }
984
985 static void mkfs_stub (XDR *xdr_in)
986 {
987   int r;
988   struct guestfs_mkfs_args args;
989   const char *fstype;
990   const char *device;
991
992   memset (&args, 0, sizeof args);
993
994   if (!xdr_guestfs_mkfs_args (xdr_in, &args)) {
995     reply_with_error ("%s: daemon failed to decode procedure arguments", "mkfs");
996     return;
997   }
998   fstype = args.fstype;
999   device = args.device;
1000
1001   r = do_mkfs (fstype, device);
1002   if (r == -1)
1003     /* do_mkfs has already called reply_with_error */
1004     goto done;
1005
1006   reply (NULL, NULL);
1007 done:
1008   xdr_free ((xdrproc_t) xdr_guestfs_mkfs_args, (char *) &args);
1009 }
1010
1011 static void sfdisk_stub (XDR *xdr_in)
1012 {
1013   int r;
1014   struct guestfs_sfdisk_args args;
1015   const char *device;
1016   int cyls;
1017   int heads;
1018   int sectors;
1019   char **lines;
1020
1021   memset (&args, 0, sizeof args);
1022
1023   if (!xdr_guestfs_sfdisk_args (xdr_in, &args)) {
1024     reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk");
1025     return;
1026   }
1027   device = args.device;
1028   cyls = args.cyls;
1029   heads = args.heads;
1030   sectors = args.sectors;
1031   args.lines.lines_val = realloc (args.lines.lines_val, sizeof (char *) * (args.lines.lines_len+1));
1032   args.lines.lines_val[args.lines.lines_len] = NULL;
1033   lines = args.lines.lines_val;
1034
1035   r = do_sfdisk (device, cyls, heads, sectors, lines);
1036   if (r == -1)
1037     /* do_sfdisk has already called reply_with_error */
1038     goto done;
1039
1040   reply (NULL, NULL);
1041 done:
1042   xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_args, (char *) &args);
1043 }
1044
1045 static void write_file_stub (XDR *xdr_in)
1046 {
1047   int r;
1048   struct guestfs_write_file_args args;
1049   const char *path;
1050   const char *content;
1051   int size;
1052
1053   memset (&args, 0, sizeof args);
1054
1055   if (!xdr_guestfs_write_file_args (xdr_in, &args)) {
1056     reply_with_error ("%s: daemon failed to decode procedure arguments", "write_file");
1057     return;
1058   }
1059   path = args.path;
1060   content = args.content;
1061   size = args.size;
1062
1063   r = do_write_file (path, content, size);
1064   if (r == -1)
1065     /* do_write_file has already called reply_with_error */
1066     goto done;
1067
1068   reply (NULL, NULL);
1069 done:
1070   xdr_free ((xdrproc_t) xdr_guestfs_write_file_args, (char *) &args);
1071 }
1072
1073 static void umount_stub (XDR *xdr_in)
1074 {
1075   int r;
1076   struct guestfs_umount_args args;
1077   const char *pathordevice;
1078
1079   memset (&args, 0, sizeof args);
1080
1081   if (!xdr_guestfs_umount_args (xdr_in, &args)) {
1082     reply_with_error ("%s: daemon failed to decode procedure arguments", "umount");
1083     return;
1084   }
1085   pathordevice = args.pathordevice;
1086
1087   r = do_umount (pathordevice);
1088   if (r == -1)
1089     /* do_umount has already called reply_with_error */
1090     goto done;
1091
1092   reply (NULL, NULL);
1093 done:
1094   xdr_free ((xdrproc_t) xdr_guestfs_umount_args, (char *) &args);
1095 }
1096
1097 static void mounts_stub (XDR *xdr_in)
1098 {
1099   char **r;
1100
1101   r = do_mounts ();
1102   if (r == NULL)
1103     /* do_mounts has already called reply_with_error */
1104     goto done;
1105
1106   struct guestfs_mounts_ret ret;
1107   ret.devices.devices_len = count_strings (r);
1108   ret.devices.devices_val = r;
1109   reply ((xdrproc_t) &xdr_guestfs_mounts_ret, (char *) &ret);
1110   free_strings (r);
1111 done: ;
1112 }
1113
1114 static void umount_all_stub (XDR *xdr_in)
1115 {
1116   int r;
1117
1118   r = do_umount_all ();
1119   if (r == -1)
1120     /* do_umount_all has already called reply_with_error */
1121     goto done;
1122
1123   reply (NULL, NULL);
1124 done: ;
1125 }
1126
1127 static void lvm_remove_all_stub (XDR *xdr_in)
1128 {
1129   int r;
1130
1131   r = do_lvm_remove_all ();
1132   if (r == -1)
1133     /* do_lvm_remove_all has already called reply_with_error */
1134     goto done;
1135
1136   reply (NULL, NULL);
1137 done: ;
1138 }
1139
1140 static void file_stub (XDR *xdr_in)
1141 {
1142   char *r;
1143   struct guestfs_file_args args;
1144   const char *path;
1145
1146   memset (&args, 0, sizeof args);
1147
1148   if (!xdr_guestfs_file_args (xdr_in, &args)) {
1149     reply_with_error ("%s: daemon failed to decode procedure arguments", "file");
1150     return;
1151   }
1152   path = args.path;
1153
1154   r = do_file (path);
1155   if (r == NULL)
1156     /* do_file has already called reply_with_error */
1157     goto done;
1158
1159   struct guestfs_file_ret ret;
1160   ret.description = r;
1161   reply ((xdrproc_t) &xdr_guestfs_file_ret, (char *) &ret);
1162   free (r);
1163 done:
1164   xdr_free ((xdrproc_t) xdr_guestfs_file_args, (char *) &args);
1165 }
1166
1167 void dispatch_incoming_message (XDR *xdr_in)
1168 {
1169   switch (proc_nr) {
1170     case GUESTFS_PROC_MOUNT:
1171       mount_stub (xdr_in);
1172       break;
1173     case GUESTFS_PROC_SYNC:
1174       sync_stub (xdr_in);
1175       break;
1176     case GUESTFS_PROC_TOUCH:
1177       touch_stub (xdr_in);
1178       break;
1179     case GUESTFS_PROC_CAT:
1180       cat_stub (xdr_in);
1181       break;
1182     case GUESTFS_PROC_LL:
1183       ll_stub (xdr_in);
1184       break;
1185     case GUESTFS_PROC_LS:
1186       ls_stub (xdr_in);
1187       break;
1188     case GUESTFS_PROC_LIST_DEVICES:
1189       list_devices_stub (xdr_in);
1190       break;
1191     case GUESTFS_PROC_LIST_PARTITIONS:
1192       list_partitions_stub (xdr_in);
1193       break;
1194     case GUESTFS_PROC_PVS:
1195       pvs_stub (xdr_in);
1196       break;
1197     case GUESTFS_PROC_VGS:
1198       vgs_stub (xdr_in);
1199       break;
1200     case GUESTFS_PROC_LVS:
1201       lvs_stub (xdr_in);
1202       break;
1203     case GUESTFS_PROC_PVS_FULL:
1204       pvs_full_stub (xdr_in);
1205       break;
1206     case GUESTFS_PROC_VGS_FULL:
1207       vgs_full_stub (xdr_in);
1208       break;
1209     case GUESTFS_PROC_LVS_FULL:
1210       lvs_full_stub (xdr_in);
1211       break;
1212     case GUESTFS_PROC_READ_LINES:
1213       read_lines_stub (xdr_in);
1214       break;
1215     case GUESTFS_PROC_AUG_INIT:
1216       aug_init_stub (xdr_in);
1217       break;
1218     case GUESTFS_PROC_AUG_CLOSE:
1219       aug_close_stub (xdr_in);
1220       break;
1221     case GUESTFS_PROC_AUG_DEFVAR:
1222       aug_defvar_stub (xdr_in);
1223       break;
1224     case GUESTFS_PROC_AUG_DEFNODE:
1225       aug_defnode_stub (xdr_in);
1226       break;
1227     case GUESTFS_PROC_AUG_GET:
1228       aug_get_stub (xdr_in);
1229       break;
1230     case GUESTFS_PROC_AUG_SET:
1231       aug_set_stub (xdr_in);
1232       break;
1233     case GUESTFS_PROC_AUG_INSERT:
1234       aug_insert_stub (xdr_in);
1235       break;
1236     case GUESTFS_PROC_AUG_RM:
1237       aug_rm_stub (xdr_in);
1238       break;
1239     case GUESTFS_PROC_AUG_MV:
1240       aug_mv_stub (xdr_in);
1241       break;
1242     case GUESTFS_PROC_AUG_MATCH:
1243       aug_match_stub (xdr_in);
1244       break;
1245     case GUESTFS_PROC_AUG_SAVE:
1246       aug_save_stub (xdr_in);
1247       break;
1248     case GUESTFS_PROC_AUG_LOAD:
1249       aug_load_stub (xdr_in);
1250       break;
1251     case GUESTFS_PROC_AUG_LS:
1252       aug_ls_stub (xdr_in);
1253       break;
1254     case GUESTFS_PROC_RM:
1255       rm_stub (xdr_in);
1256       break;
1257     case GUESTFS_PROC_RMDIR:
1258       rmdir_stub (xdr_in);
1259       break;
1260     case GUESTFS_PROC_RM_RF:
1261       rm_rf_stub (xdr_in);
1262       break;
1263     case GUESTFS_PROC_MKDIR:
1264       mkdir_stub (xdr_in);
1265       break;
1266     case GUESTFS_PROC_MKDIR_P:
1267       mkdir_p_stub (xdr_in);
1268       break;
1269     case GUESTFS_PROC_CHMOD:
1270       chmod_stub (xdr_in);
1271       break;
1272     case GUESTFS_PROC_CHOWN:
1273       chown_stub (xdr_in);
1274       break;
1275     case GUESTFS_PROC_EXISTS:
1276       exists_stub (xdr_in);
1277       break;
1278     case GUESTFS_PROC_IS_FILE:
1279       is_file_stub (xdr_in);
1280       break;
1281     case GUESTFS_PROC_IS_DIR:
1282       is_dir_stub (xdr_in);
1283       break;
1284     case GUESTFS_PROC_PVCREATE:
1285       pvcreate_stub (xdr_in);
1286       break;
1287     case GUESTFS_PROC_VGCREATE:
1288       vgcreate_stub (xdr_in);
1289       break;
1290     case GUESTFS_PROC_LVCREATE:
1291       lvcreate_stub (xdr_in);
1292       break;
1293     case GUESTFS_PROC_MKFS:
1294       mkfs_stub (xdr_in);
1295       break;
1296     case GUESTFS_PROC_SFDISK:
1297       sfdisk_stub (xdr_in);
1298       break;
1299     case GUESTFS_PROC_WRITE_FILE:
1300       write_file_stub (xdr_in);
1301       break;
1302     case GUESTFS_PROC_UMOUNT:
1303       umount_stub (xdr_in);
1304       break;
1305     case GUESTFS_PROC_MOUNTS:
1306       mounts_stub (xdr_in);
1307       break;
1308     case GUESTFS_PROC_UMOUNT_ALL:
1309       umount_all_stub (xdr_in);
1310       break;
1311     case GUESTFS_PROC_LVM_REMOVE_ALL:
1312       lvm_remove_all_stub (xdr_in);
1313       break;
1314     case GUESTFS_PROC_FILE:
1315       file_stub (xdr_in);
1316       break;
1317     default:
1318       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
1319   }
1320 }
1321
1322 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";
1323
1324 static int lvm_tokenize_pv (char *str, struct guestfs_lvm_int_pv *r)
1325 {
1326   char *tok, *p, *next;
1327   int i, j;
1328
1329   if (!str) {
1330     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
1331     return -1;
1332   }
1333   if (!*str || isspace (*str)) {
1334     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
1335     return -1;
1336   }
1337   tok = str;
1338   if (!tok) {
1339     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_name");
1340     return -1;
1341   }
1342   p = strchrnul (tok, ',');
1343   if (*p) next = p+1; else next = NULL;
1344   *p = '\0';
1345   r->pv_name = strdup (tok);
1346   if (r->pv_name == NULL) {
1347     perror ("strdup");
1348     return -1;
1349   }
1350   tok = next;
1351   if (!tok) {
1352     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_uuid");
1353     return -1;
1354   }
1355   p = strchrnul (tok, ',');
1356   if (*p) next = p+1; else next = NULL;
1357   *p = '\0';
1358   for (i = j = 0; i < 32; ++j) {
1359     if (tok[j] == '\0') {
1360       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1361       return -1;
1362     } else if (tok[j] != '-')
1363       r->pv_uuid[i++] = tok[j];
1364   }
1365   tok = next;
1366   if (!tok) {
1367     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_fmt");
1368     return -1;
1369   }
1370   p = strchrnul (tok, ',');
1371   if (*p) next = p+1; else next = NULL;
1372   *p = '\0';
1373   r->pv_fmt = strdup (tok);
1374   if (r->pv_fmt == NULL) {
1375     perror ("strdup");
1376     return -1;
1377   }
1378   tok = next;
1379   if (!tok) {
1380     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_size");
1381     return -1;
1382   }
1383   p = strchrnul (tok, ',');
1384   if (*p) next = p+1; else next = NULL;
1385   *p = '\0';
1386   if (sscanf (tok, "%"SCNu64, &r->pv_size) != 1) {
1387     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_size");
1388     return -1;
1389   }
1390   tok = next;
1391   if (!tok) {
1392     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "dev_size");
1393     return -1;
1394   }
1395   p = strchrnul (tok, ',');
1396   if (*p) next = p+1; else next = NULL;
1397   *p = '\0';
1398   if (sscanf (tok, "%"SCNu64, &r->dev_size) != 1) {
1399     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "dev_size");
1400     return -1;
1401   }
1402   tok = next;
1403   if (!tok) {
1404     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_free");
1405     return -1;
1406   }
1407   p = strchrnul (tok, ',');
1408   if (*p) next = p+1; else next = NULL;
1409   *p = '\0';
1410   if (sscanf (tok, "%"SCNu64, &r->pv_free) != 1) {
1411     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_free");
1412     return -1;
1413   }
1414   tok = next;
1415   if (!tok) {
1416     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_used");
1417     return -1;
1418   }
1419   p = strchrnul (tok, ',');
1420   if (*p) next = p+1; else next = NULL;
1421   *p = '\0';
1422   if (sscanf (tok, "%"SCNu64, &r->pv_used) != 1) {
1423     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_used");
1424     return -1;
1425   }
1426   tok = next;
1427   if (!tok) {
1428     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_attr");
1429     return -1;
1430   }
1431   p = strchrnul (tok, ',');
1432   if (*p) next = p+1; else next = NULL;
1433   *p = '\0';
1434   r->pv_attr = strdup (tok);
1435   if (r->pv_attr == NULL) {
1436     perror ("strdup");
1437     return -1;
1438   }
1439   tok = next;
1440   if (!tok) {
1441     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_count");
1442     return -1;
1443   }
1444   p = strchrnul (tok, ',');
1445   if (*p) next = p+1; else next = NULL;
1446   *p = '\0';
1447   if (sscanf (tok, "%"SCNi64, &r->pv_pe_count) != 1) {
1448     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_count");
1449     return -1;
1450   }
1451   tok = next;
1452   if (!tok) {
1453     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_alloc_count");
1454     return -1;
1455   }
1456   p = strchrnul (tok, ',');
1457   if (*p) next = p+1; else next = NULL;
1458   *p = '\0';
1459   if (sscanf (tok, "%"SCNi64, &r->pv_pe_alloc_count) != 1) {
1460     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_alloc_count");
1461     return -1;
1462   }
1463   tok = next;
1464   if (!tok) {
1465     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_tags");
1466     return -1;
1467   }
1468   p = strchrnul (tok, ',');
1469   if (*p) next = p+1; else next = NULL;
1470   *p = '\0';
1471   r->pv_tags = strdup (tok);
1472   if (r->pv_tags == NULL) {
1473     perror ("strdup");
1474     return -1;
1475   }
1476   tok = next;
1477   if (!tok) {
1478     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pe_start");
1479     return -1;
1480   }
1481   p = strchrnul (tok, ',');
1482   if (*p) next = p+1; else next = NULL;
1483   *p = '\0';
1484   if (sscanf (tok, "%"SCNu64, &r->pe_start) != 1) {
1485     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pe_start");
1486     return -1;
1487   }
1488   tok = next;
1489   if (!tok) {
1490     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_count");
1491     return -1;
1492   }
1493   p = strchrnul (tok, ',');
1494   if (*p) next = p+1; else next = NULL;
1495   *p = '\0';
1496   if (sscanf (tok, "%"SCNi64, &r->pv_mda_count) != 1) {
1497     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_mda_count");
1498     return -1;
1499   }
1500   tok = next;
1501   if (!tok) {
1502     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_free");
1503     return -1;
1504   }
1505   p = strchrnul (tok, ',');
1506   if (*p) next = p+1; else next = NULL;
1507   *p = '\0';
1508   if (sscanf (tok, "%"SCNu64, &r->pv_mda_free) != 1) {
1509     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_mda_free");
1510     return -1;
1511   }
1512   tok = next;
1513   if (tok != NULL) {
1514     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1515     return -1;
1516   }
1517   return 0;
1518 }
1519
1520 guestfs_lvm_int_pv_list *
1521 parse_command_line_pvs (void)
1522 {
1523   char *out, *err;
1524   char *p, *pend;
1525   int r, i;
1526   guestfs_lvm_int_pv_list *ret;
1527   void *newp;
1528
1529   ret = malloc (sizeof *ret);
1530   if (!ret) {
1531     reply_with_perror ("malloc");
1532     return NULL;
1533   }
1534
1535   ret->guestfs_lvm_int_pv_list_len = 0;
1536   ret->guestfs_lvm_int_pv_list_val = NULL;
1537
1538   r = command (&out, &err,
1539                "/sbin/lvm", "pvs",
1540                "-o", lvm_pv_cols, "--unbuffered", "--noheadings",
1541                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1542   if (r == -1) {
1543     reply_with_error ("%s", err);
1544     free (out);
1545     free (err);
1546     return NULL;
1547   }
1548
1549   free (err);
1550
1551   /* Tokenize each line of the output. */
1552   p = out;
1553   i = 0;
1554   while (p) {
1555     pend = strchr (p, '\n');    /* Get the next line of output. */
1556     if (pend) {
1557       *pend = '\0';
1558       pend++;
1559     }
1560
1561     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1562       p++;
1563
1564     if (!*p) {                  /* Empty line?  Skip it. */
1565       p = pend;
1566       continue;
1567     }
1568
1569     /* Allocate some space to store this next entry. */
1570     newp = realloc (ret->guestfs_lvm_int_pv_list_val,
1571                     sizeof (guestfs_lvm_int_pv) * (i+1));
1572     if (newp == NULL) {
1573       reply_with_perror ("realloc");
1574       free (ret->guestfs_lvm_int_pv_list_val);
1575       free (ret);
1576       free (out);
1577       return NULL;
1578     }
1579     ret->guestfs_lvm_int_pv_list_val = newp;
1580
1581     /* Tokenize the next entry. */
1582     r = lvm_tokenize_pv (p, &ret->guestfs_lvm_int_pv_list_val[i]);
1583     if (r == -1) {
1584       reply_with_error ("failed to parse output of 'pvs' command");
1585       free (ret->guestfs_lvm_int_pv_list_val);
1586       free (ret);
1587       free (out);
1588       return NULL;
1589     }
1590
1591     ++i;
1592     p = pend;
1593   }
1594
1595   ret->guestfs_lvm_int_pv_list_len = i;
1596
1597   free (out);
1598   return ret;
1599 }
1600 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";
1601
1602 static int lvm_tokenize_vg (char *str, struct guestfs_lvm_int_vg *r)
1603 {
1604   char *tok, *p, *next;
1605   int i, j;
1606
1607   if (!str) {
1608     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
1609     return -1;
1610   }
1611   if (!*str || isspace (*str)) {
1612     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
1613     return -1;
1614   }
1615   tok = str;
1616   if (!tok) {
1617     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_name");
1618     return -1;
1619   }
1620   p = strchrnul (tok, ',');
1621   if (*p) next = p+1; else next = NULL;
1622   *p = '\0';
1623   r->vg_name = strdup (tok);
1624   if (r->vg_name == NULL) {
1625     perror ("strdup");
1626     return -1;
1627   }
1628   tok = next;
1629   if (!tok) {
1630     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_uuid");
1631     return -1;
1632   }
1633   p = strchrnul (tok, ',');
1634   if (*p) next = p+1; else next = NULL;
1635   *p = '\0';
1636   for (i = j = 0; i < 32; ++j) {
1637     if (tok[j] == '\0') {
1638       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1639       return -1;
1640     } else if (tok[j] != '-')
1641       r->vg_uuid[i++] = tok[j];
1642   }
1643   tok = next;
1644   if (!tok) {
1645     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_fmt");
1646     return -1;
1647   }
1648   p = strchrnul (tok, ',');
1649   if (*p) next = p+1; else next = NULL;
1650   *p = '\0';
1651   r->vg_fmt = strdup (tok);
1652   if (r->vg_fmt == NULL) {
1653     perror ("strdup");
1654     return -1;
1655   }
1656   tok = next;
1657   if (!tok) {
1658     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_attr");
1659     return -1;
1660   }
1661   p = strchrnul (tok, ',');
1662   if (*p) next = p+1; else next = NULL;
1663   *p = '\0';
1664   r->vg_attr = strdup (tok);
1665   if (r->vg_attr == NULL) {
1666     perror ("strdup");
1667     return -1;
1668   }
1669   tok = next;
1670   if (!tok) {
1671     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_size");
1672     return -1;
1673   }
1674   p = strchrnul (tok, ',');
1675   if (*p) next = p+1; else next = NULL;
1676   *p = '\0';
1677   if (sscanf (tok, "%"SCNu64, &r->vg_size) != 1) {
1678     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_size");
1679     return -1;
1680   }
1681   tok = next;
1682   if (!tok) {
1683     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free");
1684     return -1;
1685   }
1686   p = strchrnul (tok, ',');
1687   if (*p) next = p+1; else next = NULL;
1688   *p = '\0';
1689   if (sscanf (tok, "%"SCNu64, &r->vg_free) != 1) {
1690     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_free");
1691     return -1;
1692   }
1693   tok = next;
1694   if (!tok) {
1695     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_sysid");
1696     return -1;
1697   }
1698   p = strchrnul (tok, ',');
1699   if (*p) next = p+1; else next = NULL;
1700   *p = '\0';
1701   r->vg_sysid = strdup (tok);
1702   if (r->vg_sysid == NULL) {
1703     perror ("strdup");
1704     return -1;
1705   }
1706   tok = next;
1707   if (!tok) {
1708     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_size");
1709     return -1;
1710   }
1711   p = strchrnul (tok, ',');
1712   if (*p) next = p+1; else next = NULL;
1713   *p = '\0';
1714   if (sscanf (tok, "%"SCNu64, &r->vg_extent_size) != 1) {
1715     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_extent_size");
1716     return -1;
1717   }
1718   tok = next;
1719   if (!tok) {
1720     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_count");
1721     return -1;
1722   }
1723   p = strchrnul (tok, ',');
1724   if (*p) next = p+1; else next = NULL;
1725   *p = '\0';
1726   if (sscanf (tok, "%"SCNi64, &r->vg_extent_count) != 1) {
1727     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_extent_count");
1728     return -1;
1729   }
1730   tok = next;
1731   if (!tok) {
1732     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free_count");
1733     return -1;
1734   }
1735   p = strchrnul (tok, ',');
1736   if (*p) next = p+1; else next = NULL;
1737   *p = '\0';
1738   if (sscanf (tok, "%"SCNi64, &r->vg_free_count) != 1) {
1739     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_free_count");
1740     return -1;
1741   }
1742   tok = next;
1743   if (!tok) {
1744     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_lv");
1745     return -1;
1746   }
1747   p = strchrnul (tok, ',');
1748   if (*p) next = p+1; else next = NULL;
1749   *p = '\0';
1750   if (sscanf (tok, "%"SCNi64, &r->max_lv) != 1) {
1751     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_lv");
1752     return -1;
1753   }
1754   tok = next;
1755   if (!tok) {
1756     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_pv");
1757     return -1;
1758   }
1759   p = strchrnul (tok, ',');
1760   if (*p) next = p+1; else next = NULL;
1761   *p = '\0';
1762   if (sscanf (tok, "%"SCNi64, &r->max_pv) != 1) {
1763     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_pv");
1764     return -1;
1765   }
1766   tok = next;
1767   if (!tok) {
1768     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_count");
1769     return -1;
1770   }
1771   p = strchrnul (tok, ',');
1772   if (*p) next = p+1; else next = NULL;
1773   *p = '\0';
1774   if (sscanf (tok, "%"SCNi64, &r->pv_count) != 1) {
1775     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_count");
1776     return -1;
1777   }
1778   tok = next;
1779   if (!tok) {
1780     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_count");
1781     return -1;
1782   }
1783   p = strchrnul (tok, ',');
1784   if (*p) next = p+1; else next = NULL;
1785   *p = '\0';
1786   if (sscanf (tok, "%"SCNi64, &r->lv_count) != 1) {
1787     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_count");
1788     return -1;
1789   }
1790   tok = next;
1791   if (!tok) {
1792     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_count");
1793     return -1;
1794   }
1795   p = strchrnul (tok, ',');
1796   if (*p) next = p+1; else next = NULL;
1797   *p = '\0';
1798   if (sscanf (tok, "%"SCNi64, &r->snap_count) != 1) {
1799     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "snap_count");
1800     return -1;
1801   }
1802   tok = next;
1803   if (!tok) {
1804     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_seqno");
1805     return -1;
1806   }
1807   p = strchrnul (tok, ',');
1808   if (*p) next = p+1; else next = NULL;
1809   *p = '\0';
1810   if (sscanf (tok, "%"SCNi64, &r->vg_seqno) != 1) {
1811     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_seqno");
1812     return -1;
1813   }
1814   tok = next;
1815   if (!tok) {
1816     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_tags");
1817     return -1;
1818   }
1819   p = strchrnul (tok, ',');
1820   if (*p) next = p+1; else next = NULL;
1821   *p = '\0';
1822   r->vg_tags = strdup (tok);
1823   if (r->vg_tags == NULL) {
1824     perror ("strdup");
1825     return -1;
1826   }
1827   tok = next;
1828   if (!tok) {
1829     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_count");
1830     return -1;
1831   }
1832   p = strchrnul (tok, ',');
1833   if (*p) next = p+1; else next = NULL;
1834   *p = '\0';
1835   if (sscanf (tok, "%"SCNi64, &r->vg_mda_count) != 1) {
1836     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_mda_count");
1837     return -1;
1838   }
1839   tok = next;
1840   if (!tok) {
1841     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_free");
1842     return -1;
1843   }
1844   p = strchrnul (tok, ',');
1845   if (*p) next = p+1; else next = NULL;
1846   *p = '\0';
1847   if (sscanf (tok, "%"SCNu64, &r->vg_mda_free) != 1) {
1848     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_mda_free");
1849     return -1;
1850   }
1851   tok = next;
1852   if (tok != NULL) {
1853     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
1854     return -1;
1855   }
1856   return 0;
1857 }
1858
1859 guestfs_lvm_int_vg_list *
1860 parse_command_line_vgs (void)
1861 {
1862   char *out, *err;
1863   char *p, *pend;
1864   int r, i;
1865   guestfs_lvm_int_vg_list *ret;
1866   void *newp;
1867
1868   ret = malloc (sizeof *ret);
1869   if (!ret) {
1870     reply_with_perror ("malloc");
1871     return NULL;
1872   }
1873
1874   ret->guestfs_lvm_int_vg_list_len = 0;
1875   ret->guestfs_lvm_int_vg_list_val = NULL;
1876
1877   r = command (&out, &err,
1878                "/sbin/lvm", "vgs",
1879                "-o", lvm_vg_cols, "--unbuffered", "--noheadings",
1880                "--nosuffix", "--separator", ",", "--units", "b", NULL);
1881   if (r == -1) {
1882     reply_with_error ("%s", err);
1883     free (out);
1884     free (err);
1885     return NULL;
1886   }
1887
1888   free (err);
1889
1890   /* Tokenize each line of the output. */
1891   p = out;
1892   i = 0;
1893   while (p) {
1894     pend = strchr (p, '\n');    /* Get the next line of output. */
1895     if (pend) {
1896       *pend = '\0';
1897       pend++;
1898     }
1899
1900     while (*p && isspace (*p))  /* Skip any leading whitespace. */
1901       p++;
1902
1903     if (!*p) {                  /* Empty line?  Skip it. */
1904       p = pend;
1905       continue;
1906     }
1907
1908     /* Allocate some space to store this next entry. */
1909     newp = realloc (ret->guestfs_lvm_int_vg_list_val,
1910                     sizeof (guestfs_lvm_int_vg) * (i+1));
1911     if (newp == NULL) {
1912       reply_with_perror ("realloc");
1913       free (ret->guestfs_lvm_int_vg_list_val);
1914       free (ret);
1915       free (out);
1916       return NULL;
1917     }
1918     ret->guestfs_lvm_int_vg_list_val = newp;
1919
1920     /* Tokenize the next entry. */
1921     r = lvm_tokenize_vg (p, &ret->guestfs_lvm_int_vg_list_val[i]);
1922     if (r == -1) {
1923       reply_with_error ("failed to parse output of 'vgs' command");
1924       free (ret->guestfs_lvm_int_vg_list_val);
1925       free (ret);
1926       free (out);
1927       return NULL;
1928     }
1929
1930     ++i;
1931     p = pend;
1932   }
1933
1934   ret->guestfs_lvm_int_vg_list_len = i;
1935
1936   free (out);
1937   return ret;
1938 }
1939 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";
1940
1941 static int lvm_tokenize_lv (char *str, struct guestfs_lvm_int_lv *r)
1942 {
1943   char *tok, *p, *next;
1944   int i, j;
1945
1946   if (!str) {
1947     fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
1948     return -1;
1949   }
1950   if (!*str || isspace (*str)) {
1951     fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
1952     return -1;
1953   }
1954   tok = str;
1955   if (!tok) {
1956     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_name");
1957     return -1;
1958   }
1959   p = strchrnul (tok, ',');
1960   if (*p) next = p+1; else next = NULL;
1961   *p = '\0';
1962   r->lv_name = strdup (tok);
1963   if (r->lv_name == NULL) {
1964     perror ("strdup");
1965     return -1;
1966   }
1967   tok = next;
1968   if (!tok) {
1969     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_uuid");
1970     return -1;
1971   }
1972   p = strchrnul (tok, ',');
1973   if (*p) next = p+1; else next = NULL;
1974   *p = '\0';
1975   for (i = j = 0; i < 32; ++j) {
1976     if (tok[j] == '\0') {
1977       fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
1978       return -1;
1979     } else if (tok[j] != '-')
1980       r->lv_uuid[i++] = tok[j];
1981   }
1982   tok = next;
1983   if (!tok) {
1984     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_attr");
1985     return -1;
1986   }
1987   p = strchrnul (tok, ',');
1988   if (*p) next = p+1; else next = NULL;
1989   *p = '\0';
1990   r->lv_attr = strdup (tok);
1991   if (r->lv_attr == NULL) {
1992     perror ("strdup");
1993     return -1;
1994   }
1995   tok = next;
1996   if (!tok) {
1997     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_major");
1998     return -1;
1999   }
2000   p = strchrnul (tok, ',');
2001   if (*p) next = p+1; else next = NULL;
2002   *p = '\0';
2003   if (sscanf (tok, "%"SCNi64, &r->lv_major) != 1) {
2004     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_major");
2005     return -1;
2006   }
2007   tok = next;
2008   if (!tok) {
2009     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_minor");
2010     return -1;
2011   }
2012   p = strchrnul (tok, ',');
2013   if (*p) next = p+1; else next = NULL;
2014   *p = '\0';
2015   if (sscanf (tok, "%"SCNi64, &r->lv_minor) != 1) {
2016     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_minor");
2017     return -1;
2018   }
2019   tok = next;
2020   if (!tok) {
2021     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_major");
2022     return -1;
2023   }
2024   p = strchrnul (tok, ',');
2025   if (*p) next = p+1; else next = NULL;
2026   *p = '\0';
2027   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_major) != 1) {
2028     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_major");
2029     return -1;
2030   }
2031   tok = next;
2032   if (!tok) {
2033     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_minor");
2034     return -1;
2035   }
2036   p = strchrnul (tok, ',');
2037   if (*p) next = p+1; else next = NULL;
2038   *p = '\0';
2039   if (sscanf (tok, "%"SCNi64, &r->lv_kernel_minor) != 1) {
2040     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_minor");
2041     return -1;
2042   }
2043   tok = next;
2044   if (!tok) {
2045     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_size");
2046     return -1;
2047   }
2048   p = strchrnul (tok, ',');
2049   if (*p) next = p+1; else next = NULL;
2050   *p = '\0';
2051   if (sscanf (tok, "%"SCNu64, &r->lv_size) != 1) {
2052     fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "lv_size");
2053     return -1;
2054   }
2055   tok = next;
2056   if (!tok) {
2057     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "seg_count");
2058     return -1;
2059   }
2060   p = strchrnul (tok, ',');
2061   if (*p) next = p+1; else next = NULL;
2062   *p = '\0';
2063   if (sscanf (tok, "%"SCNi64, &r->seg_count) != 1) {
2064     fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "seg_count");
2065     return -1;
2066   }
2067   tok = next;
2068   if (!tok) {
2069     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "origin");
2070     return -1;
2071   }
2072   p = strchrnul (tok, ',');
2073   if (*p) next = p+1; else next = NULL;
2074   *p = '\0';
2075   r->origin = strdup (tok);
2076   if (r->origin == NULL) {
2077     perror ("strdup");
2078     return -1;
2079   }
2080   tok = next;
2081   if (!tok) {
2082     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_percent");
2083     return -1;
2084   }
2085   p = strchrnul (tok, ',');
2086   if (*p) next = p+1; else next = NULL;
2087   *p = '\0';
2088   if (tok[0] == '\0')
2089     r->snap_percent = -1;
2090   else if (sscanf (tok, "%f", &r->snap_percent) != 1) {
2091     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "snap_percent");
2092     return -1;
2093   }
2094   tok = next;
2095   if (!tok) {
2096     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "copy_percent");
2097     return -1;
2098   }
2099   p = strchrnul (tok, ',');
2100   if (*p) next = p+1; else next = NULL;
2101   *p = '\0';
2102   if (tok[0] == '\0')
2103     r->copy_percent = -1;
2104   else if (sscanf (tok, "%f", &r->copy_percent) != 1) {
2105     fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "copy_percent");
2106     return -1;
2107   }
2108   tok = next;
2109   if (!tok) {
2110     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "move_pv");
2111     return -1;
2112   }
2113   p = strchrnul (tok, ',');
2114   if (*p) next = p+1; else next = NULL;
2115   *p = '\0';
2116   r->move_pv = strdup (tok);
2117   if (r->move_pv == NULL) {
2118     perror ("strdup");
2119     return -1;
2120   }
2121   tok = next;
2122   if (!tok) {
2123     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_tags");
2124     return -1;
2125   }
2126   p = strchrnul (tok, ',');
2127   if (*p) next = p+1; else next = NULL;
2128   *p = '\0';
2129   r->lv_tags = strdup (tok);
2130   if (r->lv_tags == NULL) {
2131     perror ("strdup");
2132     return -1;
2133   }
2134   tok = next;
2135   if (!tok) {
2136     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "mirror_log");
2137     return -1;
2138   }
2139   p = strchrnul (tok, ',');
2140   if (*p) next = p+1; else next = NULL;
2141   *p = '\0';
2142   r->mirror_log = strdup (tok);
2143   if (r->mirror_log == NULL) {
2144     perror ("strdup");
2145     return -1;
2146   }
2147   tok = next;
2148   if (!tok) {
2149     fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "modules");
2150     return -1;
2151   }
2152   p = strchrnul (tok, ',');
2153   if (*p) next = p+1; else next = NULL;
2154   *p = '\0';
2155   r->modules = strdup (tok);
2156   if (r->modules == NULL) {
2157     perror ("strdup");
2158     return -1;
2159   }
2160   tok = next;
2161   if (tok != NULL) {
2162     fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
2163     return -1;
2164   }
2165   return 0;
2166 }
2167
2168 guestfs_lvm_int_lv_list *
2169 parse_command_line_lvs (void)
2170 {
2171   char *out, *err;
2172   char *p, *pend;
2173   int r, i;
2174   guestfs_lvm_int_lv_list *ret;
2175   void *newp;
2176
2177   ret = malloc (sizeof *ret);
2178   if (!ret) {
2179     reply_with_perror ("malloc");
2180     return NULL;
2181   }
2182
2183   ret->guestfs_lvm_int_lv_list_len = 0;
2184   ret->guestfs_lvm_int_lv_list_val = NULL;
2185
2186   r = command (&out, &err,
2187                "/sbin/lvm", "lvs",
2188                "-o", lvm_lv_cols, "--unbuffered", "--noheadings",
2189                "--nosuffix", "--separator", ",", "--units", "b", NULL);
2190   if (r == -1) {
2191     reply_with_error ("%s", err);
2192     free (out);
2193     free (err);
2194     return NULL;
2195   }
2196
2197   free (err);
2198
2199   /* Tokenize each line of the output. */
2200   p = out;
2201   i = 0;
2202   while (p) {
2203     pend = strchr (p, '\n');    /* Get the next line of output. */
2204     if (pend) {
2205       *pend = '\0';
2206       pend++;
2207     }
2208
2209     while (*p && isspace (*p))  /* Skip any leading whitespace. */
2210       p++;
2211
2212     if (!*p) {                  /* Empty line?  Skip it. */
2213       p = pend;
2214       continue;
2215     }
2216
2217     /* Allocate some space to store this next entry. */
2218     newp = realloc (ret->guestfs_lvm_int_lv_list_val,
2219                     sizeof (guestfs_lvm_int_lv) * (i+1));
2220     if (newp == NULL) {
2221       reply_with_perror ("realloc");
2222       free (ret->guestfs_lvm_int_lv_list_val);
2223       free (ret);
2224       free (out);
2225       return NULL;
2226     }
2227     ret->guestfs_lvm_int_lv_list_val = newp;
2228
2229     /* Tokenize the next entry. */
2230     r = lvm_tokenize_lv (p, &ret->guestfs_lvm_int_lv_list_val[i]);
2231     if (r == -1) {
2232       reply_with_error ("failed to parse output of 'lvs' command");
2233       free (ret->guestfs_lvm_int_lv_list_val);
2234       free (ret);
2235       free (out);
2236       return NULL;
2237     }
2238
2239     ++i;
2240     p = pend;
2241   }
2242
2243   ret->guestfs_lvm_int_lv_list_len = i;
2244
2245   free (out);
2246   return ret;
2247 }