]> sourceware.org Git - newlib-cygwin.git/blobdiff - winsup/utils/mount.cc
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / mount.cc
index 00c662e62de908a04cb94fb84a4b2c08848fc4f1..a65a6e5776653cd1709a3523c36ebcb702b8f3a1 100644 (file)
@@ -1,7 +1,5 @@
 /* mount.cc
 
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
-
 This file is part of Cygwin.
 
 This software is a copyrighted work licensed under the terms of the
@@ -14,22 +12,27 @@ details. */
 #include <mntent.h>
 #include <windows.h>
 #include <sys/cygwin.h>
+#include <cygwin/version.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <getopt.h>
+#include <dirent.h>
+#include "path.h"
 
-#ifdef errno
-#undef errno
-#endif
 #include <errno.h>
 
-static void mount_commands (void);
+#define NT_MAX_PATH 32768
+
+#define EXEC_FLAGS (MOUNT_EXEC | MOUNT_NOTEXEC | MOUNT_CYGWIN_EXEC)
+
+static void mount_entries (void);
 static void show_mounts (void);
 static void show_cygdrive_info (void);
 static void change_cygdrive_prefix (const char *new_prefix, int flags);
 static int mount_already_exists (const char *posix_path, int flags);
 
 // static short create_missing_dirs = FALSE;
-static short force = FALSE;
+static bool force = false;
 
 static const char *progname;
 
@@ -48,12 +51,9 @@ static void
 do_mount (const char *dev, const char *where, int flags)
 {
   struct stat statbuf;
-  char win32_path[MAX_PATH];
   int statres;
 
-  cygwin_conv_to_win32_path (where, win32_path);
-
-  statres = stat (win32_path, &statbuf);
+  statres = stat (where, &statbuf);
 
 #if 0
   if (statres == -1)
@@ -69,64 +69,187 @@ do_mount (const char *dev, const char *where, int flags)
     }
 #endif
 
-  if (mount (dev, where, flags))
-    error (where);
-
   if (statres == -1)
     {
-      if (force == FALSE)
+      if (!force)
        fprintf (stderr, "%s: warning - %s does not exist.\n", progname, where);
     }
   else if (!(statbuf.st_mode & S_IFDIR))
     {
-      if (force == FALSE)
-       fprintf (stderr, "%s: warning: %s is not a directory.\n", progname, where);
+      if (!force)
+       fprintf (stderr, "%s: warning: %s is not a directory.\n",
+                progname, where);
     }
 
-  exit (0);
+  if (!force && !(flags & (EXEC_FLAGS | MOUNT_BIND)) && strlen (dev))
+    {
+      char devtmp[1 + 2 * strlen (dev)];
+      strcpy (devtmp, dev);
+      char c = strchr (devtmp, '\0')[-1];
+      if (c == '/' || c == '\\')
+       strcat (devtmp, ".");
+      /* Use a curious property of Windows which allows the use of \.. even
+        on non-directory paths. */
+      for (const char *p = dev; (p = strpbrk (p, "/\\")); p++)
+       strcat (devtmp, "\\..");
+      strcat (devtmp, "\\");
+      if (GetDriveType (devtmp) == DRIVE_REMOTE)
+       {
+         fprintf (stderr,
+      "%s: defaulting to 'notexec' mount option for speed since native path\n"
+      "%*creferences a remote share.  Use '-f' option to override.\n",
+                  progname, (int) strlen(progname) + 2, ' ');
+         flags |= MOUNT_NOTEXEC;
+       }
+    }
+
+  if (mount (dev, where, flags))
+    error (where);
 }
 
-struct option longopts[] =
+static void
+from_fstab (bool user)
 {
-  {"help", no_argument, NULL, 'h' },
-  {"binary", no_argument, NULL, 'b'},
-  {"force", no_argument, NULL, 'f'},
-  {"system", no_argument, NULL, 's'},
-  {"text", no_argument, NULL, 't'},
-  {"user", no_argument, NULL, 'u'},
-  {"executable", no_argument, NULL, 'x'},
+  char path[PATH_MAX];
+  char buf[65536];
+  mnt_t *m = mount_table + max_mount_entry;
+
+  strcpy (path, "/etc/fstab");
+  if (user)
+    {
+      strcat (path, ".d/");
+      strcat (path, getlogin ());
+    }
+  FILE *fh = fopen (path, "rt");
+  if (!fh)
+    return;
+  while (fgets (buf, 65536, fh))
+    {
+      char *c = strrchr (buf, '\n');
+      if (c)
+       *c = '\0';
+      if (from_fstab_line (m, buf, user))
+       ++m;
+    }
+  max_mount_entry = m - mount_table;
+  fclose (fh);
+}
+
+static void
+do_mount_from_fstab (const char *where)
+{
+  force = true;
+  /* Read fstab entries. */
+  from_fstab (false);
+  from_fstab (true);
+  /* Loop through fstab entries and see if it matches `where'.  If `where'
+     is NULL, all entries match. */
+  bool exists = false;
+  for (mnt_t *m = mount_table; m - mount_table < max_mount_entry; ++m)
+    if (!where || !strcmp (where, m->posix))
+      {
+       if (m->flags & MOUNT_CYGDRIVE)
+         {
+           /* Get the cygdrive info */
+           char user[MAX_PATH];
+           char system[MAX_PATH];
+           char user_flags[MAX_PATH];
+           char system_flags[MAX_PATH];
+
+           exists = true;
+           cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags,
+                            system_flags);
+           if ((*user && strcmp (user, m->posix) != 0)
+               || (*system && strcmp (system, m->posix) != 0))
+             if (mount (NULL, m->posix, m->flags))
+               error (m->posix);
+         }
+       else
+         {
+           exists = true;
+           /* Compare with existing mount table.  If the entry doesn't exist,
+              mount it. */
+           FILE *mt = setmntent ("/-not-used-", "r");
+           struct mntent *p;
+
+           while ((p = getmntent (mt)) != NULL)
+             if (!strcmp (m->posix, p->mnt_dir))
+               break;
+           if (!p)
+             do_mount (m->native, m->posix, m->flags);
+           endmntent (mt);
+           if (where)
+             break;
+         }
+      }
+  if (!exists && where)
+    fprintf (stderr,
+            "%s: can't find %s in /etc/fstab or in /etc/fstab.d/$USER\n",
+            progname, where);
+}
+
+static struct option longopts[] =
+{
+  {"all", no_argument, NULL, 'a'},
   {"change-cygdrive-prefix", no_argument, NULL, 'c'},
-  {"cygwin-executable", no_argument, NULL, 'X'},
+  {"force", no_argument, NULL, 'f'},
+  {"help", no_argument, NULL, 'h' },
+  {"mount-entries", no_argument, NULL, 'm'},
+  {"options", required_argument, NULL, 'o'},
   {"show-cygdrive-prefix", no_argument, NULL, 'p'},
-  {"import-old-mounts", no_argument, NULL, 'i'},
-  {"mount-commands", no_argument, NULL, 'm'},
+  {"version", no_argument, NULL, 'V'},
   {NULL, 0, NULL, 0}
 };
 
-char opts[] = "hbfstuxXpicm";
+static char opts[] = "acfhmpVo:";
 
-static void
-usage (void)
+static void __attribute__ ((__noreturn__))
+usage (FILE *where = stderr)
 {
-  fprintf (stderr, "Usage: %s [OPTION] [<win32path> <posixpath>]\n\
-  -b, --binary                  text files are equivalent to binary files\n\
-                               (newline = \\n)\n\
+  char *options;
+
+  fprintf (where, "Usage: %1$s [OPTION] [<win32path> <posixpath>]\n\
+       %1$s -a\n\
+       %1$s <posixpath>\n\
+\n\
+Display information about mounted filesystems, or mount a filesystem\n\
+\n\
+  -a, --all                     mount all filesystems mentioned in fstab\n\
   -c, --change-cygdrive-prefix  change the cygdrive path prefix to <posixpath>\n\
   -f, --force                   force mount, don't warn about missing mount\n\
                                point directories\n\
-  -i, --import-old-mounts       copy old registry mount table mounts into the\n\
-                                current mount areas\n\
+  -h, --help                    output usage information and exit\n\
+  -m, --mount-entries           write fstab entries to replicate mount points\n\
+                               and cygdrive prefixes\n\
+  -o, --options X[,X...]       specify mount options\n\
   -p, --show-cygdrive-prefix    show user and/or system cygdrive path prefix\n\
-  -s, --system                  add mount point to system-wide registry location\n\
-  -t, --text       (default)    text files get \\r\\n line endings\n\
-  -u, --user       (default)    add mount point to user registry location\n\
-  -x, --executable              treat all files under mount point as executables\n\
-  -X, --cygwin-executable       treat all files under mount point as cygwin\n\
-                               executables\n\
-  -m, --mount-commands          write mount commands to replace user and\n\
-                               system mount points and cygdrive prefixes\n\
-", progname);
-  exit (1);
+  -V, --version                 output version information and exit\n\n",
+  progname);
+  if (!cygwin_internal (CW_LST_MNT_OPTS, &options))
+    fprintf (where, "Valid options are: %s\n\n", options);
+  exit (where == stderr ? 1 : 0);
+}
+
+static void
+print_version ()
+{
+  printf ("mount (cygwin) %d.%d.%d\n"
+         "Mount filesystem utility\n"
+         "Copyright (C) 1996 - %s Cygwin Authors\n"
+         "This is free software; see the source for copying conditions.  There is NO\n"
+         "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+         CYGWIN_VERSION_DLL_MAJOR / 1000,
+         CYGWIN_VERSION_DLL_MAJOR % 1000,
+         CYGWIN_VERSION_DLL_MINOR,
+         strrchr (__DATE__, ' ') + 1);
+}
+
+static char *
+concat3 (char *a, const char *b, const char *c)
+{
+  size_t totlen = strlen (a) + strlen (b) + strlen (c) + 1;
+  a = (char *) realloc (a, totlen);
+  return strcat (strcat (a, b), c);
 }
 
 int
@@ -134,16 +257,17 @@ main (int argc, char **argv)
 {
   int i;
   int flags = 0;
+  char *options = strdup ("");
   enum do_what
   {
     nada,
     saw_change_cygdrive_prefix,
-    saw_import_old_mounts,
     saw_show_cygdrive_prefix,
-    saw_mount_commands
+    saw_mount_commands,
+    saw_mount_all,
   } do_what = nada;
 
-  progname = argv[0];
+  progname = program_invocation_short_name;
 
   if (argc == 1)
     {
@@ -154,8 +278,11 @@ main (int argc, char **argv)
   while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
     switch (i)
       {
-      case 'b':
-       flags |= MOUNT_BINARY;
+      case 'a':
+       if (do_what == nada)
+         do_what = saw_mount_all;
+       else
+         usage ();
        break;
       case 'c':
        if (do_what == nada)
@@ -164,45 +291,55 @@ main (int argc, char **argv)
          usage ();
        break;
       case 'f':
-       force = TRUE;
+       force = true;
+       break;
+      case 'h':
+       usage (stdout);
        break;
-      case 'i':
+      case 'm':
        if (do_what == nada)
-         do_what = saw_import_old_mounts;
+         do_what = saw_mount_commands;
        else
          usage ();
        break;
+      case 'o':
+       if (do_what == saw_mount_all)
+         usage ();
+       else if (*options)
+         options = concat3 (options, ",", optarg);
+       else
+         options = strdup (optarg);
+       break;
       case 'p':
        if (do_what == nada)
          do_what = saw_show_cygdrive_prefix;
        else
          usage ();
        break;
-      case 's':
-       flags |= MOUNT_SYSTEM;
-       break;
-      case 't':
-       flags &= ~MOUNT_BINARY;
-       break;
-      case 'u':
-       flags &= ~MOUNT_SYSTEM;
-       break;
-      case 'X':
-       flags |= MOUNT_CYGWIN_EXEC;
-       break;
-      case 'x':
-       flags |= MOUNT_EXEC;
-       break;
-      case 'm':
-       if (do_what == nada)
-         do_what = saw_mount_commands;
-       else
-         usage ();
+      case 'V':
+       print_version ();
+       return 0;
        break;
       default:
-       usage ();
+       fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+       return 1;
       }
 
+  if (cygwin_internal (CW_CVT_MNT_OPTS, &options, &flags))
+    {
+      fprintf (stderr, "%s: invalid option - '%s'\n", progname, options);
+      exit (1);
+    }
+
+  if (flags & MOUNT_NOTEXEC && flags & (MOUNT_EXEC | MOUNT_CYGWIN_EXEC))
+    {
+      fprintf (stderr, "%s: invalid combination of executable options\n",
+              progname);
+      exit (1);
+    }
+
+  cygwin_internal (CW_SET_DOS_FILE_WARNING, false);
+
   argc--;
   switch (do_what)
     {
@@ -211,12 +348,6 @@ main (int argc, char **argv)
        usage ();
       change_cygdrive_prefix (argv[optind], flags);
       break;
-    case saw_import_old_mounts:
-      if (optind <= argc)
-       usage ();
-      else
-       cygwin_internal (CW_READ_V1_MOUNT_TABLES);
-      break;
     case saw_show_cygdrive_prefix:
       if (optind <= argc)
        usage ();
@@ -225,18 +356,22 @@ main (int argc, char **argv)
     case saw_mount_commands:
       if (optind <= argc)
        usage ();
-      mount_commands ();
+      mount_entries ();
+      break;
+    case saw_mount_all:
+      if (optind <= argc)
+       usage ();
+      do_mount_from_fstab (NULL);
       break;
     default:
-      if (optind != (argc - 1))
+      if (optind == argc)
+       do_mount_from_fstab (argv[optind]);
+      else if (optind != (argc - 1))
        {
-         if (optind >= argc)
-           fprintf (stderr, "%s: not enough arguments\n", progname);
-         else
-           fprintf (stderr, "%s: too many arguments\n", progname);
+         fprintf (stderr, "%s: too many arguments\n", progname);
          usage ();
        }
-      if (force || !mount_already_exists (argv[optind + 1], flags))
+      else if (force || !mount_already_exists (argv[optind + 1], flags))
        do_mount (argv[optind], argv[optind + 1], flags);
       else
        {
@@ -249,61 +384,72 @@ main (int argc, char **argv)
   return 0;
 }
 
+static char *
+convert_spaces (char *tgt, const char *src)
+{
+  char *tp, *spacep;
+  const char *sp;
+
+  tp = tgt;
+  for (sp = src; (spacep = strchr (sp, ' ')); sp = spacep + 1)
+    {
+      tp = stpncpy (tp, sp, spacep - sp);
+      tp = stpcpy (tp, "\\040");
+    }
+  stpcpy (tp, sp);
+  return tgt;
+}
+
 static void
-mount_commands (void)
+mount_entries (void)
 {
   FILE *m = setmntent ("/-not-used-", "r");
   struct mntent *p;
-  char *c;
-  const char *format_mnt = "mount%s \"%s\" \"%s\"\n";
-  const char *format_cyg = "mount%s --change-cygdrive-prefix \"%s\"\n";
-  char opts[MAX_PATH];
-  char user[MAX_PATH];
-  char system[MAX_PATH];
-  char user_flags[MAX_PATH];
-  char system_flags[MAX_PATH];
+  const char *format_mnt = "%s %s %s %s 0 0\n";
+  const char *format_cyg = "none %s cygdrive %s 0 0\n";
 
-  // write mount commands for user and system mount points
-  while ((p = getmntent (m)) != NULL) {
-    // Only list non-cygdrives
-    if (!strstr (p->mnt_opts, ",noumount")) {
-      strcpy(opts, " -f");
-      if      (p->mnt_type[0] == 'u')
-        strcat (opts, " -u");
-      else if (p->mnt_type[0] == 's')
-        strcat (opts, " -s");
-      if      (p->mnt_opts[0] == 'b')
-        strcat (opts, " -b");
-      else if (p->mnt_opts[0] == 't')
-        strcat (opts, " -t");
-      if (strstr (p->mnt_opts, ",exec"))
-        strcat (opts, " -x");
-      while ((c = strchr (p->mnt_fsname, '\\')) != NULL)
-        *c = '/';
-      printf (format_mnt, opts, p->mnt_fsname, p->mnt_dir);
-    }
-  }
+  // write fstab entries for normal mount points
+  while ((p = getmntent (m)) != NULL)
+    // Only list non-cygdrives and non-automounts
+    if (!strstr (p->mnt_opts, ",noumount") && !strstr (p->mnt_opts, ",auto"))
+      {
+       char fsname[NT_MAX_PATH], dirname[NT_MAX_PATH];
+       /* Drop the "bind" option since it can't be reverted. */
+       char *c = strstr (p->mnt_opts, ",bind");
+       if (c)
+         memmove (c, c + 5, strlen (c + 5) + 1);
+       printf (format_mnt, convert_spaces (fsname, p->mnt_fsname),
+                           convert_spaces (dirname, p->mnt_dir),
+                           p->mnt_type, p->mnt_opts);
+      }
   endmntent (m);
 
-  // write mount commands for cygdrive prefixes
-  cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags,
-                  system_flags);
-  if (strlen (user) > 0) {
-    strcpy (opts, "   ");
-    if      (user_flags[0] == 'b')
-      strcat (opts, " -b");
-    else if (user_flags[0] == 't')
-      strcat (opts, " -t");
-    printf (format_cyg, opts, user);
-  }
-  if (strlen (system) > 0) {
-    strcpy (opts, " -s");
-    if      (system_flags[0] == 'b')
-      strcat (opts, " -b");
-    else if (system_flags[0] == 't')
-      strcat (opts, " -t");
-    printf (format_cyg, opts, system);
-  }
+  // write fstab entry for cygdrive prefix
+  m = setmntent ("/-not-used-", "r");
+  while ((p = getmntent (m)) != NULL)
+    {
+      char *noumount;
+      if ((noumount = strstr (p->mnt_opts, ",noumount")))
+       {
+         char dirname[NT_MAX_PATH];
+         char opts[strlen (p->mnt_opts) + 1];
+
+         convert_spaces (dirname, p->mnt_dir);
+         // remove trailing slash
+         char *ls = strrchr (dirname, '/');
+         if (ls)
+           {
+             // last slash == leading slash?  cygdrive prefix == "/"
+             if (ls == dirname)
+               ++ls;
+             *ls = '\0';
+           }
+         *stpncpy (opts, p->mnt_opts, noumount - p->mnt_opts) = '\0';
+         printf (format_cyg, dirname, opts);
+         break;
+       }
+    }
+  endmntent (m);
 
   exit(0);
 }
@@ -354,13 +500,13 @@ mount_already_exists (const char *posix_path, int flags)
              else
                fprintf (stderr,
                         "%s: warning: user mount point of '%s' "
-                        "masks system mount.\n",
-                        progname, posix_path);
+                        "masks system mount.\n", progname, posix_path);
              break;
            }
          else
            {
-             fprintf (stderr, "%s: warning: couldn't determine mount type.\n", progname);
+             fprintf (stderr, "%s: warning: couldn't determine mount type.\n",
+                      progname);
              break;
            }
        }
@@ -374,7 +520,7 @@ mount_already_exists (const char *posix_path, int flags)
 static void
 change_cygdrive_prefix (const char *new_prefix, int flags)
 {
-  flags |= MOUNT_AUTO;
+  flags |= MOUNT_CYGDRIVE;
 
   if (mount (NULL, new_prefix, flags))
     error (new_prefix);
@@ -402,7 +548,7 @@ show_cygdrive_info ()
   if (strlen (user) > 0)
     printf (format, user, "user", user_flags);
   if (strlen (system) > 0)
-    printf (format, system, "system", system_flags);
+    printf (format, system, "nouser", system_flags);
 
   exit (0);
 }
This page took 0.034732 seconds and 5 git commands to generate.