3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 #include <sys/mount.h>
17 #include <sys/cygwin.h>
18 #include <cygwin/version.h>
30 #define NT_MAX_PATH 32768
32 #define EXEC_FLAGS (MOUNT_EXEC | MOUNT_NOTEXEC | MOUNT_CYGWIN_EXEC)
34 static void mount_entries (void);
35 static void show_mounts (void);
36 static void show_cygdrive_info (void);
37 static void change_cygdrive_prefix (const char *new_prefix
, int flags
);
38 static int mount_already_exists (const char *posix_path
, int flags
);
40 // static short create_missing_dirs = FALSE;
41 static bool force
= false;
43 static const char *progname
;
46 error (const char *path
)
48 fprintf (stderr
, "%s: %s: %s\n", progname
, path
,
49 (errno
== EMFILE
) ? "Too many mount entries" : strerror (errno
));
53 /* FIXME: do_mount should also print a warning message if the dev arg
54 is a non-existent Win32 path. */
57 do_mount (const char *dev
, const char *where
, int flags
)
62 statres
= stat (where
, &statbuf
);
67 /* FIXME: this'll fail if mount dir is missing any parent dirs */
68 if (create_missing_dirs
== TRUE
)
70 if (mkdir (where
, 0755) == -1)
71 fprintf (stderr
, "Warning: unable to create %s!\n", where
);
73 statres
= 0; /* Pretend stat succeeded if we could mkdir. */
81 fprintf (stderr
, "%s: warning - %s does not exist.\n", progname
, where
);
83 else if (!(statbuf
.st_mode
& S_IFDIR
))
86 fprintf (stderr
, "%s: warning: %s is not a directory.\n",
90 if (!force
&& !(flags
& (EXEC_FLAGS
| MOUNT_BIND
)) && strlen (dev
))
92 char devtmp
[1 + 2 * strlen (dev
)];
94 char c
= strchr (devtmp
, '\0')[-1];
95 if (c
== '/' || c
== '\\')
97 /* Use a curious property of Windows which allows the use of \.. even
98 on non-directory paths. */
99 for (const char *p
= dev
; (p
= strpbrk (p
, "/\\")); p
++)
100 strcat (devtmp
, "\\..");
101 strcat (devtmp
, "\\");
102 if (GetDriveType (devtmp
) == DRIVE_REMOTE
)
105 "%s: defaulting to 'notexec' mount option for speed since native path\n"
106 "%*creferences a remote share. Use '-f' option to override.\n",
107 progname
, strlen(progname
) + 2, ' ');
108 flags
|= MOUNT_NOTEXEC
;
112 if (mount (dev
, where
, flags
))
117 from_fstab (bool user
)
121 mnt_t
*m
= mount_table
+ max_mount_entry
;
123 strcpy (path
, "/etc/fstab");
126 strcat (path
, ".d/");
127 strcat (path
, getlogin ());
129 FILE *fh
= fopen (path
, "rt");
132 while (fgets (buf
, 65536, fh
))
134 char *c
= strrchr (buf
, '\n');
137 if (from_fstab_line (m
, buf
, user
))
140 max_mount_entry
= m
- mount_table
;
145 do_mount_from_fstab (const char *where
)
148 /* Read fstab entries. */
151 /* Loop through fstab entries and see if it matches `where'. If `where'
152 is NULL, all entries match. */
154 for (mnt_t
*m
= mount_table
; m
- mount_table
< max_mount_entry
; ++m
)
155 if (!where
|| !strcmp (where
, m
->posix
))
157 if (m
->flags
& MOUNT_CYGDRIVE
)
159 /* Get the cygdrive info */
161 char system
[MAX_PATH
];
162 char user_flags
[MAX_PATH
];
163 char system_flags
[MAX_PATH
];
166 cygwin_internal (CW_GET_CYGDRIVE_INFO
, user
, system
, user_flags
,
168 if ((*user
&& strcmp (user
, m
->posix
) != 0)
169 || (*system
&& strcmp (system
, m
->posix
) != 0))
170 if (mount (NULL
, m
->posix
, m
->flags
))
176 /* Compare with existing mount table. If the entry doesn't exist,
178 FILE *mt
= setmntent ("/-not-used-", "r");
181 while ((p
= getmntent (mt
)) != NULL
)
182 if (!strcmp (m
->posix
, p
->mnt_dir
))
185 do_mount (m
->native
, m
->posix
, m
->flags
);
191 if (!exists
&& where
)
193 "%s: can't find %s in /etc/fstab or in /etc/fstab.d/$USER\n",
197 static struct option longopts
[] =
199 {"all", no_argument
, NULL
, 'a'},
200 {"change-cygdrive-prefix", no_argument
, NULL
, 'c'},
201 {"force", no_argument
, NULL
, 'f'},
202 {"help", no_argument
, NULL
, 'h' },
203 {"mount-entries", no_argument
, NULL
, 'm'},
204 {"options", required_argument
, NULL
, 'o'},
205 {"show-cygdrive-prefix", no_argument
, NULL
, 'p'},
206 {"version", no_argument
, NULL
, 'V'},
210 static char opts
[] = "acfhmpVo:";
213 usage (FILE *where
= stderr
)
217 fprintf (where
, "Usage: %1$s [OPTION] [<win32path> <posixpath>]\n\
221 Display information about mounted filesystems, or mount a filesystem\n\
223 -a, --all mount all filesystems mentioned in fstab\n\
224 -c, --change-cygdrive-prefix change the cygdrive path prefix to <posixpath>\n\
225 -f, --force force mount, don't warn about missing mount\n\
227 -h, --help output usage information and exit\n\
228 -m, --mount-entries write fstab entries to replicate mount points\n\
229 and cygdrive prefixes\n\
230 -o, --options X[,X...] specify mount options\n\
231 -p, --show-cygdrive-prefix show user and/or system cygdrive path prefix\n\
232 -V, --version output version information and exit\n\n",
234 if (!cygwin_internal (CW_LST_MNT_OPTS
, &options
))
235 fprintf (where
, "Valid options are: %s\n\n", options
);
236 exit (where
== stderr
? 1 : 0);
242 printf ("mount (cygwin) %d.%d.%d\n"
243 "Mount filesystem utility\n"
244 "Copyright (C) 1996 - %s Red Hat, Inc.\n"
245 "This is free software; see the source for copying conditions. There is NO\n"
246 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
247 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
248 CYGWIN_VERSION_DLL_MAJOR
% 1000,
249 CYGWIN_VERSION_DLL_MINOR
,
250 strrchr (__DATE__
, ' ') + 1);
254 concat3 (char *a
, const char *b
, const char *c
)
256 size_t totlen
= strlen (a
) + strlen (b
) + strlen (c
) + 1;
257 a
= (char *) realloc (a
, totlen
);
258 return strcat (strcat (a
, b
), c
);
262 main (int argc
, char **argv
)
265 int flags
= MOUNT_BINARY
;
266 char *options
= strdup ("");
270 saw_change_cygdrive_prefix
,
271 saw_show_cygdrive_prefix
,
276 progname
= program_invocation_short_name
;
284 while ((i
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
289 do_what
= saw_mount_all
;
295 do_what
= saw_change_cygdrive_prefix
;
307 do_what
= saw_mount_commands
;
312 if (do_what
== saw_mount_all
)
315 options
= concat3 (options
, ",", optarg
);
317 options
= strdup (optarg
);
321 do_what
= saw_show_cygdrive_prefix
;
330 fprintf (stderr
, "Try `%s --help' for more information.\n", progname
);
334 if (cygwin_internal (CW_CVT_MNT_OPTS
, &options
, &flags
))
336 fprintf (stderr
, "%s: invalid option - '%s'\n", progname
, options
);
340 if (flags
& MOUNT_NOTEXEC
&& flags
& (MOUNT_EXEC
| MOUNT_CYGWIN_EXEC
))
342 fprintf (stderr
, "%s: invalid combination of executable options\n",
347 cygwin_internal (CW_SET_DOS_FILE_WARNING
, false);
352 case saw_change_cygdrive_prefix
:
355 change_cygdrive_prefix (argv
[optind
], flags
);
357 case saw_show_cygdrive_prefix
:
360 show_cygdrive_info ();
362 case saw_mount_commands
:
370 do_mount_from_fstab (NULL
);
374 do_mount_from_fstab (argv
[optind
]);
375 else if (optind
!= (argc
- 1))
377 fprintf (stderr
, "%s: too many arguments\n", progname
);
380 else if (force
|| !mount_already_exists (argv
[optind
+ 1], flags
))
381 do_mount (argv
[optind
], argv
[optind
+ 1], flags
);
385 error (argv
[optind
+ 1]);
394 convert_spaces (char *tgt
, const char *src
)
400 for (sp
= src
; (spacep
= strchr (sp
, ' ')); sp
= spacep
+ 1)
402 tp
= stpncpy (tp
, sp
, spacep
- sp
);
403 tp
= stpcpy (tp
, "\\040");
412 FILE *m
= setmntent ("/-not-used-", "r");
414 const char *format_mnt
= "%s %s %s %s 0 0\n";
415 const char *format_cyg
= "none %s cygdrive %s 0 0\n";
417 // write fstab entries for normal mount points
418 while ((p
= getmntent (m
)) != NULL
)
419 // Only list non-cygdrives and non-automounts
420 if (!strstr (p
->mnt_opts
, ",noumount") && !strstr (p
->mnt_opts
, ",auto"))
422 char fsname
[NT_MAX_PATH
], dirname
[NT_MAX_PATH
];
423 /* Drop the "bind" option since it can't be reverted. */
424 char *c
= strstr (p
->mnt_opts
, ",bind");
426 memmove (c
, c
+ 5, strlen (c
+ 5) + 1);
427 printf (format_mnt
, convert_spaces (fsname
, p
->mnt_fsname
),
428 convert_spaces (dirname
, p
->mnt_dir
),
429 p
->mnt_type
, p
->mnt_opts
);
433 // write fstab entry for cygdrive prefix
434 m
= setmntent ("/-not-used-", "r");
435 while ((p
= getmntent (m
)) != NULL
)
438 if ((noumount
= strstr (p
->mnt_opts
, ",noumount")))
440 char dirname
[NT_MAX_PATH
];
441 char opts
[strlen (p
->mnt_opts
) + 1];
443 convert_spaces (dirname
, p
->mnt_dir
);
444 // remove trailing slash
445 char *ls
= strrchr (dirname
, '/');
448 // last slash == leading slash? cygdrive prefix == "/"
453 *stpncpy (opts
, p
->mnt_opts
, noumount
- p
->mnt_opts
) = '\0';
454 printf (format_cyg
, dirname
, opts
);
466 FILE *m
= setmntent ("/-not-used-", "r");
468 const char *format
= "%s on %s type %s (%s)\n";
470 // printf (format, "Device", "Directory", "Type", "Flags");
471 while ((p
= getmntent (m
)) != NULL
)
472 printf (format
, p
->mnt_fsname
, p
->mnt_dir
, p
->mnt_type
, p
->mnt_opts
);
476 /* Return 1 if mountpoint from the same registry area is already in
477 mount table. Otherwise return 0. */
479 mount_already_exists (const char *posix_path
, int flags
)
481 int found_matching
= 0;
483 FILE *m
= setmntent ("/-not-used-", "r");
486 while ((p
= getmntent (m
)) != NULL
)
488 /* if the paths match, and they're both the same type of mount. */
489 if (strcmp (p
->mnt_dir
, posix_path
) == 0)
491 if (p
->mnt_type
[0] == 'u')
493 if (!(flags
& MOUNT_SYSTEM
)) /* both current_user */
497 "%s: warning: system mount point of '%s' "
498 "will always be masked by user mount.\n",
499 progname
, posix_path
);
502 else if (p
->mnt_type
[0] == 's')
504 if (flags
& MOUNT_SYSTEM
) /* both system */
508 "%s: warning: user mount point of '%s' "
509 "masks system mount.\n", progname
, posix_path
);
514 fprintf (stderr
, "%s: warning: couldn't determine mount type.\n",
522 return found_matching
;
525 /* change_cygdrive_prefix: Change the cygdrive prefix */
527 change_cygdrive_prefix (const char *new_prefix
, int flags
)
529 flags
|= MOUNT_CYGDRIVE
;
531 if (mount (NULL
, new_prefix
, flags
))
537 /* show_cygdrive_info: Show the user and/or cygdrive info, i.e., prefix and
540 show_cygdrive_info ()
542 /* Get the cygdrive info */
544 char system
[MAX_PATH
];
545 char user_flags
[MAX_PATH
];
546 char system_flags
[MAX_PATH
];
547 cygwin_internal (CW_GET_CYGDRIVE_INFO
, user
, system
, user_flags
,
550 /* Display the user and system cygdrive path prefix, if necessary
552 const char *format
= "%-18s %-11s %s\n";
553 printf (format
, "Prefix", "Type", "Flags");
554 if (strlen (user
) > 0)
555 printf (format
, user
, "user", user_flags
);
556 if (strlen (system
) > 0)
557 printf (format
, system
, "nouser", system_flags
);