fuse: Return EXIT_FAILURE if fuse_main fails.
[libguestfs.git] / fish / options.c
index 55bcf68..48c8e1c 100644 (file)
@@ -1,5 +1,5 @@
 /* libguestfs - guestfish and guestmount shared option parsing
- * Copyright (C) 2010 Red Hat Inc.
+ * Copyright (C) 2010-2011 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "c-ctype.h"
+
 #include "guestfs.h"
 
 #include "options.h"
@@ -41,6 +43,11 @@ add_drives (struct drv *drv, char next_drive)
   if (drv) {
     next_drive = add_drives (drv->next, next_drive);
 
+    if (asprintf (&drv->device, "/dev/sd%c", next_drive) == -1) {
+      perror ("asprintf");
+      exit (EXIT_FAILURE);
+    }
+
     switch (drv->type) {
     case drv_a:
       ad_optargs.bitmask = 0;
@@ -56,6 +63,7 @@ add_drives (struct drv *drv, char next_drive)
       if (r == -1)
         exit (EXIT_FAILURE);
 
+      drv->nr_drives = 1;
       next_drive++;
       break;
 
@@ -64,6 +72,7 @@ add_drives (struct drv *drv, char next_drive)
       if (r == -1)
         exit (EXIT_FAILURE);
 
+      drv->nr_drives = r;
       next_drive += r;
       break;
 
@@ -78,11 +87,7 @@ add_drives (struct drv *drv, char next_drive)
       if (r == -1)
         exit (EXIT_FAILURE);
 
-      if (asprintf (&drv->N.device, "/dev/sd%c", next_drive) == -1) {
-        perror ("asprintf");
-        exit (EXIT_FAILURE);
-      }
-
+      drv->nr_drives = 1;
       next_drive++;
       break;
 
@@ -94,6 +99,9 @@ add_drives (struct drv *drv, char next_drive)
   return next_drive;
 }
 
+static void display_mountpoints_on_failure (const char *mp_device);
+static void canonical_device_name (char *dev);
+
 /* List is built in reverse order, so mount them in reverse order. */
 void
 mount_mps (struct mp *mp)
@@ -103,42 +111,81 @@ mount_mps (struct mp *mp)
   if (mp) {
     mount_mps (mp->next);
 
+    const char *options;
+    if (mp->options)
+      options = mp->options;
+    else if (read_only)
+      options = "ro";
+    else
+      options = "";
+
     /* Don't use guestfs_mount here because that will default to mount
      * options -o sync,noatime.  For more information, see guestfs(3)
      * section "LIBGUESTFS GOTCHAS".
      */
-    const char *options = read_only ? "ro" : "";
     r = guestfs_mount_options (g, options, mp->device, mp->mountpoint);
     if (r == -1) {
-      /* Display possible mountpoints before exiting. */
-      char **fses = guestfs_list_filesystems (g);
-      if (fses == NULL || fses[0] == NULL)
-        goto out;
-      fprintf (stderr,
-               _("%s: '%s' could not be mounted.  Did you mean one of these?\n"),
-               program_name, mp->device);
-      size_t i;
-      for (i = 0; fses[i] != NULL; i += 2)
-        fprintf (stderr, "\t%s (%s)\n", fses[i], fses[i+1]);
-
-    out:
+      display_mountpoints_on_failure (mp->device);
       exit (EXIT_FAILURE);
     }
   }
 }
 
+/* If the -m option fails on any command, display a useful error
+ * message listing the mountpoints.
+ */
+static void
+display_mountpoints_on_failure (const char *mp_device)
+{
+  char **fses;
+  size_t i;
+
+  fses = guestfs_list_filesystems (g);
+  if (fses == NULL)
+    return;
+  if (fses[0] == NULL) {
+    free (fses);
+    return;
+  }
+
+  fprintf (stderr,
+           _("%s: '%s' could not be mounted.  Did you mean one of these?\n"),
+           program_name, mp_device);
+
+  for (i = 0; fses[i] != NULL; i += 2) {
+    canonical_device_name (fses[i]);
+    fprintf (stderr, "\t%s (%s)\n", fses[i], fses[i+1]);
+    free (fses[i]);
+    free (fses[i+1]);
+  }
+
+  free (fses);
+}
+
+static void
+canonical_device_name (char *dev)
+{
+  if (STRPREFIX (dev, "/dev/") &&
+      (dev[5] == 'h' || dev[5] == 'v') &&
+      dev[6] == 'd' &&
+      c_isalpha (dev[7]) &&
+      (c_isdigit (dev[8]) || dev[8] == '\0'))
+    dev[5] = 's';
+}
+
 void
 free_drives (struct drv *drv)
 {
   if (!drv) return;
   free_drives (drv->next);
 
+  free (drv->device);
+
   switch (drv->type) {
   case drv_a: /* a.filename and a.format are optargs, don't free them */ break;
   case drv_d: /* d.filename is optarg, don't free it */ break;
   case drv_N:
     free (drv->N.filename);
-    free (drv->N.device);
     drv->N.data_free (drv->N.data);
     break;
   default: ;                    /* keep GCC happy */